From 348f8ab57d2498c0747c9cb4c3a42bd179e363f0 Mon Sep 17 00:00:00 2001 From: JonatanRek Date: Fri, 26 Jun 2020 16:57:26 +0200 Subject: [PATCH] Google Home API Improvement + Refactoring --- app/api/GoogleHomeApi.php | 5 +- app/models/GoogleHome.php | 478 ++++++++++++--------- app/models/types/GoogleHomeDeviceTypes.php | 93 +++- 3 files changed, 350 insertions(+), 226 deletions(-) diff --git a/app/api/GoogleHomeApi.php b/app/api/GoogleHomeApi.php index 485cd1e..b2784d4 100644 --- a/app/api/GoogleHomeApi.php +++ b/app/api/GoogleHomeApi.php @@ -16,12 +16,15 @@ class GoogleHomeApi{ case 'action.devices.QUERY': GoogleHome::query($obj['requestId'], $obj['inputs'][0]['payload']); - //$apiLogManager->write("[Google Home] action.devices.QUERY", LogRecordType::INFO); + $apiLogManager->write("[Google Home] action.devices.QUERY", LogRecordType::INFO); + $apiLogManager->write("[API] request body\n" . json_encode($obj, JSON_PRETTY_PRINT), LogRecordType::INFO); break; case 'action.devices.EXECUTE': GoogleHome::execute($obj['requestId'], $obj['inputs'][0]['payload']); $apiLogManager->write("[Google Home] action.devices.EXECUTE", LogRecordType::INFO); + $apiLogManager->write("[API] request body\n" . json_encode($obj, JSON_PRETTY_PRINT), LogRecordType::INFO); + break; } } diff --git a/app/models/GoogleHome.php b/app/models/GoogleHome.php index 0a510e4..506219c 100644 --- a/app/models/GoogleHome.php +++ b/app/models/GoogleHome.php @@ -6,40 +6,54 @@ class GoogleHome { foreach ($roomsData as $roomKey => $roomData) { $devicesData = DeviceManager::getAllDevicesInRoom($roomData['room_id']); foreach ($devicesData as $deviceKey => $deviceData) { + $traids = []; + $attributes = null; + + //Google Compatibile Action Type + $actionType = GoogleHomeDeviceTypes::getAction($deviceData['type']); + if ($actionType == "") continue; + $subDevicesData = SubDeviceManager::getAllSubDevices($deviceData['device_id']); foreach ($subDevicesData as $subDeviceKey => $subDeviceData) { - if ($subDeviceData['type'] != "on/off" && $subDeviceData['type'] != "temp_cont") continue; - - //Google Compatibile Action Type - $actionType = GoogleHomeDeviceTypes::getAction($subDeviceData['type']); - - if (strpos($deviceData['name'], 'Světlo') !== false || strpos($deviceData['name'], 'světlo') !== false) { - $actionType = 'action.devices.types.LIGHT'; + $deviceTraid = GoogleHomeDeviceTypes::getTraid($subDeviceData['type']); + if ($deviceTraid != "") { + $traids[] = $deviceTraid; } - $tempDevice = [ - 'id' => (string) $subDeviceData['subdevice_id'], - 'type' => $actionType, - 'name' => [ - 'name' => $deviceData['name'], - ], - 'willReportState' => false, - 'roomHint' => $roomData['name'] - ]; - - //traids & Attributes - $devices[] = GoogleHomeDeviceTypes::getSyncObj($tempDevice, $actionType); + $deviceAttributes = GoogleHomeDeviceTypes::getAttribute($subDeviceData['type']); + if ($deviceAttributes != "") { + $attributes = $deviceAttributes; + } } + + $tempDevice = [ + 'id' => (string) $deviceData['device_id'], + 'type' => $actionType, + 'traits' => $traids, + 'attributes' => $attributes, + 'name' => [ + 'name' => $deviceData['name'], + ], + + 'willReportState' => false, + 'roomHint' => $roomData['name'] + ]; + if ($tempDevice['attributes'] == null) unset($tempDevice['attributes']); + + //traids & Attributes + $devices[] = $tempDevice; } } + $response = [ 'requestId' => $requestId, 'payload' => [ 'agentUserId'=>'651351531531', - 'devices' => $devices, + 'devices' => array_values( $devices ), ], ]; + $apiLogManager = new LogManager('../logs/google-home/'. date("Y-m-d").'.log'); $apiLogManager->write("[API][$requestId] request response\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); echo json_encode($response); @@ -48,122 +62,59 @@ class GoogleHome { static function query($requestId, $payload){ $devices = []; foreach ($payload['devices'] as $deviceId) { - $subDeviceData = SubDeviceManager::getSubDevice($deviceId['id']); - if ($subDeviceData['type'] != "on/off" && $subDeviceData['type'] != "temp_cont") continue; - - $state = false; - if (RecordManager::getLastRecord($deviceId['id'])['value'] == 1){ - $state = true; - } - - $online = false; - $status = 'OFFLINE'; - - if (RecordManager::getLastRecord($deviceId['id'])['execuded'] == 1){ - $online = true; - $status = 'SUCCESS'; - } else { - $executed = 0; - $waiting = 0; - foreach (RecordManager::getLastRecord($deviceId['id'], 6) as $key => $value) { - if ($value['execuded'] == 1){ - $executed++; - } else { - $waiting++; - } - } - if ($waiting < $executed){ - $status = "PENDING"; - - $online = true; - } - } + $subDevicesData = SubDeviceManager::getAllSubDevices($deviceId['id']); $tempDevice = [ $deviceId['id'] => [ - 'online' => $online, - 'status'=> $status, + 'online' => false, + 'status'=> 'OFFLINE', ] ]; - if ($subDeviceData['type'] == "temp_cont"){ - $tempDevice[$deviceId['id']]['thermostatMode'] = 'off'; - if (RecordManager::getLastRecord($deviceId['id'])['value'] != 0) { - $tempDevice[$deviceId['id']]['thermostatMode'] = 'heat'; - } - $tempDevice[$deviceId['id']]['thermostatTemperatureAmbient'] = RecordManager::getLastRecord($deviceId['id'])['value']; - $tempDevice[$deviceId['id']]['thermostatTemperatureSetpoint'] = RecordManager::getLastRecord($deviceId['id'])['value']; + foreach ($subDevicesData as $key => $subDeviceData) { + $lastRecord = RecordManager::getLastRecord($subDeviceData['subdevice_id']); + if ($lastRecord['execuded'] == 1){ + $tempDevice[$deviceId['id']]['online'] = true; + $tempDevice[$deviceId['id']]['status'] = 'SUCCESS'; } else { - $tempDevice[$deviceId['id']]['on'] = $state; - } - $devices = $tempDevice; - if (count($devices)> 1){ - $devices[] = $tempDevice; - } - } - - $response = [ - 'requestId' => $requestId, - 'payload' => [ - 'devices' => $devices, - ], - ]; - - $apiLogManager = new LogManager('../logs/google-home/'. date("Y-m-d").'.log'); - $apiLogManager->write("[API][$requestId] request response\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); - echo json_encode($response); - } - - static function execute($requestId, $payload){ - $commands = []; - - foreach ($payload['commands'] as $key => $command) { - foreach ($command['devices'] as $key => $device) { - $executionCommand = $command['execution'][0]; - if (isset($command['execution'][$key])) { - $executionCommand = $command['execution'][$key]; + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($deviceId['id'], 6) as $key => $value) { + if ($value['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } } - - $subDeviceId = $device['id']; - - switch ($executionCommand['command']) { - case 'action.devices.commands.OnOff': - $commands[] = self::executeSwitch($subDeviceId, $executionCommand); - break; - - case 'action.devices.commands.ThermostatTemperatureSetpoint': - $commands[] = self::executeTermostatValue($subDeviceId, $executionCommand); - break; - - case 'action.devices.commands.ThermostatSetMode': - $commands[] = self::executeTermostatMode($subDeviceId, $executionCommand); - break; + if ($waiting < $executed){ + $tempDevice[$deviceId['id']]['online'] = true; } } + + switch ($subDeviceData['type']) { + case 'temp_cont': + $tempDevice[$deviceId['id']]['thermostatMode'] = 'off'; + if ($lastRecord['value'] != 0) { + $tempDevice[$deviceId['id']]['thermostatMode'] = 'heat'; + } + $tempDevice[$deviceId['id']]['thermostatTemperatureAmbient'] = $lastRecord['value']; + $tempDevice[$deviceId['id']]['thermostatTemperatureSetpoint'] = $lastRecord['value']; + break; + default: + $tempDevice[$deviceId['id']]['on'] = ($lastRecord['value'] == 1 ? true : false); + break; } - - $response = [ - 'requestId' => $requestId, - 'payload' => [ - 'commands' => $commands, - ], - ]; - $apiLogManager = new LogManager('../logs/google-home/'. date("Y-m-d").'.log'); - $apiLogManager->write("[API][EXECUTE][$requestId]\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); - - echo json_encode($response); } - static function executeSwitch($subDeviceId, $executionCommand){ - $value = 0; + + + if ($lastRecord['execuded'] == 1){ + $online = true; $status = 'SUCCESS'; - if ($executionCommand['params']['on']) $value = 1; - - RecordManager::createWithSubId($subDeviceId, $value); - + } else { $executed = 0; $waiting = 0; - foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) { + foreach (RecordManager::getLastRecord($deviceId['id'], 6) as $key => $value) { if ($value['execuded'] == 1){ $executed++; } else { @@ -172,92 +123,211 @@ class GoogleHome { } if ($waiting < $executed){ $status = "PENDING"; - } else { - $status = "OFFLINE"; + $online = true; } - - $commandTemp = [ - 'ids' => [$subDeviceId], - 'status' => $status, - 'states' => [ - 'on' => $executionCommand['params']['on'], - ], - ]; - return $commandTemp; } - static function executeTermostatValue($subDeviceId, $executionCommand){ - $value = 0; - $status = 'SUCCESS'; - - if (isset($executionCommand['params']['thermostatTemperatureSetpoint'])) { - $value = $executionCommand['params']['thermostatTemperatureSetpoint']; - } - - RecordManager::createWithSubId($subDeviceId, $value); - - $executed = 0; - $waiting = 0; - foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $lastValue) { - if ($lastValue['execuded'] == 1){ - $executed++; - } else { - $waiting++; - } - } - if ($waiting < $executed){ - $status = "PENDING"; - $status = "SUCCESS"; - } else { - $status = "OFFLINE"; - } - - $commandTemp = [ - 'ids' => [$subDeviceId], - 'status' => $status, - 'states' => [ - 'thermostatMode' => 'heat', - 'thermostatTemperatureSetpoint' => $value, - 'thermostatTemperatureAmbient' => $value, - //ambient z dalšího zenzoru v roomu - ], - ]; - return $commandTemp; - } - - static function executeTermostatMode($subDeviceId, $executionCommand){ - $mode = "off"; - $value = 0; - $status = "SUCCESS"; - - if (isset($executionCommand['params']['thermostatMode']) && $executionCommand['params']['thermostatMode'] != 'off') { - $mode = $executionCommand['params']['thermostatMode']; - $value = RecordManager::getLastRecordNotNull($subDeviceId)['value']; - } - - RecordManager::createWithSubId($subDeviceId, $value); - - $executed = 0; - $waiting = 0; - foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) { - if ($value['execuded'] == 1){ - $executed++; - } else { - $waiting++; - } - } - if ($waiting < $executed){ - $status = "PENDING"; - } - - $commandTemp = [ - 'ids' => [$subDeviceId], - 'status' => $status, - 'states' => [ - 'thermostatMode' => $mode - ], - ]; - - return $commandTemp; + $devices = $tempDevice; + if (count($devices)> 1){ + $devices[] = $tempDevice; } } + $response = [ + 'requestId' => $requestId, + 'payload' => [ + 'devices' => $devices, + ], + ]; + + $apiLogManager = new LogManager('../logs/google-home/'. date("Y-m-d").'.log'); + $apiLogManager->write("[API][$requestId] request response\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); + echo json_encode($response); +} + +static function execute($requestId, $payload){ + $commands = []; + + foreach ($payload['commands'] as $key => $command) { + foreach ($command['devices'] as $key => $device) { + $executionCommand = $command['execution'][0]; + if (isset($command['execution'][$key])) { + $executionCommand = $command['execution'][$key]; + } + + $deviceType = GoogleHomeDeviceTypes::getType($executionCommand['command']); + $subDeviceId = SubDeviceManager::getSubDeviceByMasterAndType($device['id'], $deviceType)['subdevice_id']; + + switch ($executionCommand['command']) { + case 'action.devices.commands.OnOff': + $commands[] = self::executeSwitch($subDeviceId, $executionCommand); + break; + + case 'action.devices.commands.ThermostatTemperatureSetpoint': + $commands[] = self::executeTermostatValue($subDeviceId, $executionCommand); + break; + + case 'action.devices.commands.ThermostatSetMode': + $commands[] = self::executeTermostatMode($subDeviceId, $executionCommand); + break; + + case 'action.devices.commands.setVolume': + $commands[] = self::executeVolume($subDeviceId, $executionCommand); + break; + + } + } + } + + $response = [ + 'requestId' => $requestId, + 'payload' => [ + 'commands' => $commands, + ], + ]; + + $apiLogManager = new LogManager('../logs/google-home/'. date("Y-m-d").'.log'); + $apiLogManager->write("[API][EXECUTE][$requestId]\n" . json_encode($response, JSON_PRETTY_PRINT), LogRecordType::INFO); + + echo json_encode($response); +} + +static function executeSwitch($subDeviceId, $executionCommand){ + $value = 0; + $status = 'SUCCESS'; + if ($executionCommand['params']['on']) $value = 1; + + RecordManager::createWithSubId($subDeviceId, $value); + + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) { + if ($value['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + } else { + $status = "OFFLINE"; + } + + $commandTemp = [ + 'ids' => [$subDeviceId], + 'status' => $status, + 'states' => [ + 'on' => $executionCommand['params']['on'], + ], + ]; + return $commandTemp; +} + +static function executeTermostatValue($subDeviceId, $executionCommand){ + $value = 0; + $status = 'SUCCESS'; + + if (isset($executionCommand['params']['thermostatTemperatureSetpoint'])) { + $value = $executionCommand['params']['thermostatTemperatureSetpoint']; + } + + RecordManager::createWithSubId($subDeviceId, $value); + + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $lastValue) { + if ($lastValue['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + $status = "SUCCESS"; + } else { + $status = "OFFLINE"; + } + + $commandTemp = [ + 'ids' => [$subDeviceId], + 'status' => $status, + 'states' => [ + 'thermostatMode' => 'heat', + 'thermostatTemperatureSetpoint' => $value, + 'thermostatTemperatureAmbient' => $value, + //ambient z dalšího zenzoru v roomu + ], + ]; + return $commandTemp; +} + +static function executeTermostatMode($subDeviceId, $executionCommand){ + $mode = "off"; + $value = 0; + $status = "SUCCESS"; + + if (isset($executionCommand['params']['thermostatMode']) && $executionCommand['params']['thermostatMode'] != 'off') { + $mode = $executionCommand['params']['thermostatMode']; + $value = RecordManager::getLastRecordNotNull($subDeviceId)['value']; + } + + RecordManager::createWithSubId($subDeviceId, $value); + + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) { + if ($value['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + } + + $commandTemp = [ + 'ids' => [$subDeviceId], + 'status' => $status, + 'states' => [ + 'thermostatMode' => $mode + ], + ]; + + return $commandTemp; +} + +static function executeVolume($subDeviceId, $executionCommand){ + $status = "SUCCESS"; + $currentVolume = RecordManager::getLastRecord($subDeviceId)['value']; + + if (isset($executionCommand['params']['volumeLevel'])) { + RecordManager::createWithSubId($subDeviceId, $executionCommand['params']['volumeLevel']); + $executed = 0; + $waiting = 0; + foreach (RecordManager::getLastRecord($subDeviceId, 4) as $key => $value) { + if ($value['execuded'] == 1){ + $executed++; + } else { + $waiting++; + } + } + if ($waiting < $executed){ + $status = "PENDING"; + } else { + $currentVolume = $executionCommand['params']['volumeLevel']; + } + } + + $commandTemp = [ + 'ids' => [$subDeviceId], + 'status' => $status, + 'states' => [ + 'currentVolume' => $currentVolume, + ], + ]; + + return $commandTemp; +} +} diff --git a/app/models/types/GoogleHomeDeviceTypes.php b/app/models/types/GoogleHomeDeviceTypes.php index 6f142b7..38023b3 100644 --- a/app/models/types/GoogleHomeDeviceTypes.php +++ b/app/models/types/GoogleHomeDeviceTypes.php @@ -72,35 +72,86 @@ class GoogleHomeDeviceTypes { const YogurtMaker = 'action.devices.types.YOGURTMAKER';*/ private static $actionWordBook = [ - 'on/off' => 'action.devices.types.OUTLET', - 'temp_cont' => 'action.devices.types.THERMOSTAT', + 'control-light' => 'action.devices.types.OUTLET', + 'control-socket' => 'action.devices.types.OUTLET', + 'control-temp' => 'action.devices.types.THERMOSTAT', + 'control-media' => 'action.devices.types.REMOTECONTROL', + ]; + + private static $traidWordBook = [ + 'on/off' => 'action.devices.traits.OnOff', + 'temp_cont' => 'action.devices.traits.TemperatureSetting', + 'vol_cont' => 'action.devices.traits.Volume', + ]; + + private static $commandWordBook = [ + 'action.devices.commands.OnOff' => 'on/off', + 'action.devices.commands.ThermostatTemperatureSetpoint' => 'temp_cont', + 'action.devices.commands.ThermostatSetMode' => 'temp_cont', + 'action.devices.commands.setVolume' => 'vol_cont', + ]; + + private static $attributeWordBook = [ + 'temp_cont' => [ + 'availableThermostatModes' => 'off,heat', + 'thermostatTemperatureUnit' => 'C' + ], + 'vol_cont' => [ + 'volumeCanMuteAndUnmute' => false, + 'volumeDefaultPercentage' => 6, + 'volumeMaxLevel' => 100, + 'levelStepSize' => 2, + 'commandOnlyVolume' => false, + ], ]; static function getAction($deviceType){ + if (!isset(self::$actionWordBook[$deviceType])) return; return self::$actionWordBook[$deviceType]; } - static function getSyncObj($deviceBaseObj, $deviceType){ - switch ($deviceType) { - case 'action.devices.types.LIGHT': - case 'action.devices.types.OUTLET': - $deviceBaseObj['traits'] = [ - 'action.devices.traits.OnOff' - ]; - break; - case 'action.devices.types.THERMOSTAT': - $deviceBaseObj['traits'] = [ - 'action.devices.traits.TemperatureSetting', - ]; - $deviceBaseObj['attributes'] = [ - "availableThermostatModes" => "off,heat", - "thermostatTemperatureUnit" => "C", - ]; - break; - } - return $deviceBaseObj; + static function getTraid($subDeviceType){ + if (!isset(self::$traidWordBook[$subDeviceType])) return; + return self::$traidWordBook[$subDeviceType]; } + static function getType($subDeviceCommand){ + if (!isset(self::$commandWordBook[$subDeviceCommand])) return; + return self::$commandWordBook[$subDeviceCommand]; + } + + static function getAttribute($subDeviceType){ + if (!isset(self::$attributeWordBook[$subDeviceType])) return; + return self::$attributeWordBook[$subDeviceType]; + } + // static function getSyncObj($deviceBaseObj, $deviceType){ + // switch ($deviceType) { + // case 'action.devices.types.LIGHT': + // case 'action.devices.types.OUTLET': + // $deviceBaseObj['traits'] = [ + // 'action.devices.traits.OnOff' + // ]; + // break; + // case 'action.devices.types.THERMOSTAT': + // $deviceBaseObj['traits'] = [ + // 'action.devices.traits.TemperatureSetting', + // ]; + // $deviceBaseObj['attributes'] = [ + // "availableThermostatModes" => "off,heat", + // "thermostatTemperatureUnit" => "C", + // ]; + // break; + // case 'action.devices.types.REMOTECONTROL': + // $deviceBaseObj['traits'] = [ + // 'action.devices.traits.Volume', + // 'action.devices.traits.MediaState', + // 'action.devices.traits.OnOff', + // ]; + // break; + // } + // return $deviceBaseObj; + // } + static function getQueryJson($deviceType, $type){ return self::$wordBook[$type]; }