From e42d656e812a2e0ae6972544ac51fd7c8082041b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 13 May 2018 15:54:05 +0100 Subject: [PATCH] domoticz: fix Onkyo custom command handling from dzVents https://github.com/domoticz/domoticz/pull/2386 Signed-off-by: David Woodhouse --- utils/domoticz/patches/101_onkyo_pr2386.patch | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 utils/domoticz/patches/101_onkyo_pr2386.patch diff --git a/utils/domoticz/patches/101_onkyo_pr2386.patch b/utils/domoticz/patches/101_onkyo_pr2386.patch new file mode 100644 index 0000000000..ce624428f1 --- /dev/null +++ b/utils/domoticz/patches/101_onkyo_pr2386.patch @@ -0,0 +1,250 @@ +From 86a4fe7e28952f969609cfb52afae06b40aa273e Mon Sep 17 00:00:00 2001 +From: David Woodhouse +Date: Sat, 12 May 2018 15:11:29 +0100 +Subject: [PATCH] Add generic CustomCommand handling for scripts + +The Onkyo-specific support in JSON and dzVents isn't really sufficient, +because it (quite rightly) needs authentication. But dzVents just assumes +it can make unauthenticated calls to localhost:8080, and doesn't work. + +I've been working around this by spawning an external script to invoke +curl, but *that* only works over HTTPS not HTTP for some reason (without +HTTPS I just get an 'Unauthorized' response). And that takes literally +*seconds* to work, on the slow machine I'm using. + +Fix it up so that the script command arrays can have a 'CustomCommand', +done generically so that it can easily cover devices other than Onkyo. +--- + .../runtime/device-adapters/onkyo_device.lua | 4 +- + hardware/DomoticzHardware.cpp | 5 ++ + hardware/DomoticzHardware.h | 1 + + hardware/OnkyoAVTCP.cpp | 4 ++ + hardware/OnkyoAVTCP.h | 1 + + main/EventSystem.cpp | 57 +++++++++++++++++++ + main/EventSystem.h | 1 + + main/SQLHelper.cpp | 4 ++ + main/SQLHelper.h | 15 ++++- + 9 files changed, 88 insertions(+), 4 deletions(-) + +diff --git a/dzVents/runtime/device-adapters/onkyo_device.lua b/dzVents/runtime/device-adapters/onkyo_device.lua +index ec74841f..8222fe6b 100644 +--- a/dzVents/runtime/device-adapters/onkyo_device.lua ++++ b/dzVents/runtime/device-adapters/onkyo_device.lua +@@ -17,9 +17,7 @@ return { + process = function (device, data, domoticz, utils, adapterManager) + + function device.onkyoEISCPCommand(cmd) +- local url = domoticz.settings['Domoticz url'] .. +- '/json.htm?param=onkyoeiscpcommand&type=command&idx=' .. device.id .. '&action=' .. tostring (cmd) +- return domoticz.openURL(url) ++ return TimedCommand(domoticz, 'CustomCommand:' .. device.id, tostring(cmd), 'device') + end + end + } +diff --git a/hardware/DomoticzHardware.cpp b/hardware/DomoticzHardware.cpp +index 7aad167b..75db53c0 100644 +--- a/hardware/DomoticzHardware.cpp ++++ b/hardware/DomoticzHardware.cpp +@@ -36,6 +36,11 @@ CDomoticzHardwareBase::~CDomoticzHardwareBase() + { + } + ++bool CDomoticzHardwareBase::CustomCommand(const uint64_t idx, const std::string &sCommand) ++{ ++ return false; ++} ++ + bool CDomoticzHardwareBase::Start() + { + m_iHBCounter = 0; +diff --git a/hardware/DomoticzHardware.h b/hardware/DomoticzHardware.h +index a8790f91..660fc2de 100644 +--- a/hardware/DomoticzHardware.h ++++ b/hardware/DomoticzHardware.h +@@ -16,6 +16,7 @@ public: + bool Start(); + bool Stop(); + virtual bool WriteToHardware(const char *pdata, const unsigned char length)=0; ++ virtual bool CustomCommand(const uint64_t idx, const std::string &sCommand); + + void EnableOutputLog(const bool bEnableLog); + +diff --git a/hardware/OnkyoAVTCP.cpp b/hardware/OnkyoAVTCP.cpp +index 88766032..9f386c01 100644 +--- a/hardware/OnkyoAVTCP.cpp ++++ b/hardware/OnkyoAVTCP.cpp +@@ -676,6 +676,10 @@ void OnkyoAVTCP::ParseData(const unsigned char *pData, int Len) + m_pPartialPkt = new_partial; + } + ++bool OnkyoAVTCP::CustomCommand(const uint64_t idx, const std::string &sCommand) ++{ ++ return SendPacket(sCommand.c_str()); ++} + + //Webserver helpers + namespace http { +diff --git a/hardware/OnkyoAVTCP.h b/hardware/OnkyoAVTCP.h +index 90dbce51..133f4876 100644 +--- a/hardware/OnkyoAVTCP.h ++++ b/hardware/OnkyoAVTCP.h +@@ -21,6 +21,7 @@ private: + int m_retrycntr; + bool StartHardware(); + bool StopHardware(); ++ bool CustomCommand(uint64_t idx, const std::string &sCommand); + unsigned char *m_pPartialPkt; + int m_PPktLen; + void ReceiveMessage(const char *pData, int Len); +diff --git a/main/EventSystem.cpp b/main/EventSystem.cpp +index cdd3968b..19562d37 100644 +--- a/main/EventSystem.cpp ++++ b/main/EventSystem.cpp +@@ -2481,6 +2481,21 @@ bool CEventSystem::parseBlocklyActions(const _tEventItem &item) + actionsDone = true; + continue; + } ++ else if (deviceName.find("CustomCommand:") == 0) ++ { ++ int idx = atoi(deviceName.substr(14).c_str()); ++ float afterTimerSeconds = 0; ++ size_t aFind = doWhat.find(" AFTER "); ++ if ((aFind > 0) && (aFind != std::string::npos)) { ++ std::string delayString = doWhat.substr(aFind + 7); ++ afterTimerSeconds = static_cast(atof(delayString.c_str())); ++ doWhat = doWhat.substr(0, aFind); ++ StripQuotes(doWhat); ++ } ++ m_sql.AddTaskItem(_tTaskItem::CustomCommand(afterTimerSeconds, idx, doWhat)); ++ actionsDone = true; ++ continue; ++ } + else + { + _log.Log(LOG_ERROR, "EventSystem: Unknown action sequence! (%s)", csubstr.c_str()); +@@ -2623,6 +2638,19 @@ bool CEventSystem::PythonScheduleEvent(std::string ID, const std::string &Action + return false; + } + ++ return true; ++ } else if(ID.find("CustomCommand:") == 0) { ++ int idx = atoi(ID.substr(14).c_str()); ++ std::string doWhat = std::string(Action); ++ float afterTimerSeconds = 0; ++ size_t aFind = Action.find(" AFTER "); ++ if ((aFind > 0) && (aFind != std::string::npos)) { ++ std::string delayString = doWhat.substr(aFind + 7); ++ doWhat = doWhat.substr(0, aFind); ++ afterTimerSeconds = static_cast(atof(delayString.c_str())); ++ StripQuotes(doWhat); ++ } ++ m_sql.AddTaskItem(_tTaskItem::CustomCommand(afterTimerSeconds, idx, doWhat)); + return true; + } + return ScheduleEvent(ID, Action,eventName); +@@ -3540,6 +3568,20 @@ bool CEventSystem::processLuaCommand(lua_State *lua_state, const std::string &fi + return false; + } + } ++ else if (lCommand.find("CustomCommand:") == 0) ++ { ++ int idx = atoi(lCommand.substr(14).c_str()); ++ std::string luaString = lua_tostring(lua_state, -1); ++ float afterTimerSeconds = 0; ++ size_t aFind = luaString.find(" AFTER "); ++ if ((aFind > 0) && (aFind != std::string::npos)) { ++ std::string delayString = luaString.substr(aFind + 7); ++ afterTimerSeconds = static_cast(atof(delayString.c_str())); ++ luaString = luaString.substr(0, aFind); ++ StripQuotes(luaString); ++ } ++ m_sql.AddTaskItem(_tTaskItem::CustomCommand(afterTimerSeconds, idx, luaString)); ++ } + else + { + if (ScheduleEvent(lua_tostring(lua_state, -2), lua_tostring(lua_state, -1), filename)) { +@@ -3557,6 +3599,21 @@ void CEventSystem::report_errors(lua_State *L, int status, std::string filename) + } + } + ++bool CEventSystem::CustomCommand(const uint64_t idx, const std::string &sCommand) ++{ ++ std::vector > result; ++ result = m_sql.safe_query("SELECT H.ID FROM DeviceStatus DS, Hardware H WHERE (DS.ID=='%u') AND (DS.HardwareID == H.ID)", idx); ++ if (result.size() != 1) ++ return false; ++ ++ int HardwareID = atoi(result[0][0].c_str()); ++ CDomoticzHardwareBase *pHardware = m_mainworker.GetHardware(HardwareID); ++ if (!pHardware) ++ return false; ++ ++ return pHardware->CustomCommand(idx, sCommand); ++} ++ + void CEventSystem::UpdateDevice(const uint64_t idx, const int nValue, const std::string &sValue, const int Protected, const bool bEventTrigger) + { + //Get device parameters +diff --git a/main/EventSystem.h b/main/EventSystem.h +index d154c4e8..cfebe2cc 100644 +--- a/main/EventSystem.h ++++ b/main/EventSystem.h +@@ -131,6 +131,7 @@ public: + bool GetEventTrigger(const uint64_t ulDevID, const _eReason reason, const bool bEventTrigger); + void SetEventTrigger(const uint64_t ulDevID, const _eReason reason, const float fDelayTime); + void UpdateDevice(const uint64_t idx, const int nValue, const std::string &sValue, const int Protected, const bool bEventTrigger = false); ++ bool CustomCommand(const uint64_t idx, const std::string &sCommand); + + void TriggerURL(const std::string &result, const std::vector &headerData, const std::string &callback); + +diff --git a/main/SQLHelper.cpp b/main/SQLHelper.cpp +index 7a46f021..0ea71d54 100644 +--- a/main/SQLHelper.cpp ++++ b/main/SQLHelper.cpp +@@ -3401,6 +3401,10 @@ void CSQLHelper::Do_Work() + { + m_mainworker.m_eventsystem.UpdateDevice(itt->_idx, itt->_nValue, itt->_sValue, itt->_HardwareID, (itt->_switchtype ? true : false)); + } ++ else if (itt->_ItemType == TITEM_CUSTOM_COMMAND) ++ { ++ m_mainworker.m_eventsystem.CustomCommand(itt->_idx, itt->_command); ++ } + + ++itt; + } +diff --git a/main/SQLHelper.h b/main/SQLHelper.h +index c0d40580..8ad60e3d 100644 +--- a/main/SQLHelper.h ++++ b/main/SQLHelper.h +@@ -49,7 +49,8 @@ enum _eTaskItemType + TITEM_SEND_NOTIFICATION, + TITEM_SET_SETPOINT, + TITEM_SEND_IFTTT_TRIGGER, +- TITEM_UPDATEDEVICE ++ TITEM_UPDATEDEVICE, ++ TITEM_CUSTOM_COMMAND, + }; + + struct _tTaskItem +@@ -261,6 +262,18 @@ struct _tTaskItem + tItem._sValue = varvalue; + tItem._command = mode; + tItem._sUntil = until; ++ ++ if (DelayTime) ++ getclock(&tItem._DelayTimeBegin); ++ return tItem; ++ } ++ static _tTaskItem CustomCommand(const float DelayTime, const uint64_t idx, const std::string &cmdstr) ++ { ++ _tTaskItem tItem; ++ tItem._ItemType = TITEM_CUSTOM_COMMAND; ++ tItem._DelayTime = DelayTime; ++ tItem._idx = idx; ++ tItem._command = cmdstr; + if (DelayTime) + getclock(&tItem._DelayTimeBegin); + return tItem; +-- +2.17.0 + -- 2.30.2