xdrv_07_domoticz.ino 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /*
  2. xdrv_07_domoticz.ino - domoticz support for Sonoff-Tasmota
  3. Copyright (C) 2018 Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifdef USE_DOMOTICZ
  16. #define XDRV_07 7
  17. const char DOMOTICZ_MESSAGE[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}";
  18. enum DomoticzCommands { CMND_IDX, CMND_KEYIDX, CMND_SWITCHIDX, CMND_SENSORIDX, CMND_UPDATETIMER };
  19. const char kDomoticzCommands[] PROGMEM = D_CMND_IDX "|" D_CMND_KEYIDX "|" D_CMND_SWITCHIDX "|" D_CMND_SENSORIDX "|" D_CMND_UPDATETIMER ;
  20. //enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_MAX_SENSORS};
  21. #if MAX_DOMOTICZ_SNS_IDX < DZ_MAX_SENSORS
  22. #error "Domoticz: Too many sensors or change settings.h layout"
  23. #endif
  24. const char kDomoticzSensors[] PROGMEM =
  25. D_DOMOTICZ_TEMP "|" D_DOMOTICZ_TEMP_HUM "|" D_DOMOTICZ_TEMP_HUM_BARO "|" D_DOMOTICZ_POWER_ENERGY "|" D_DOMOTICZ_ILLUMINANCE "|" D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT "|" D_DOMOTICZ_AIRQUALITY ;
  26. const char S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DOMOTICZ "%s%d\":%d}";
  27. const char S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE[] PROGMEM = "{\"" D_CMND_DOMOTICZ "%s%d\":%lu}";
  28. char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC;
  29. char domoticz_out_topic[] = DOMOTICZ_OUT_TOPIC;
  30. boolean domoticz_subscribe = false;
  31. byte domoticz_update_flag = 1;
  32. int domoticz_update_timer = 0;
  33. unsigned long fan_debounce = 0; // iFan02 state debounce timer
  34. int DomoticzBatteryQuality(void)
  35. {
  36. // Battery 0%: ESP 2.6V (minimum operating voltage is 2.5)
  37. // Battery 100%: ESP 3.6V (maximum operating voltage is 3.6)
  38. // Battery 101% to 200%: ESP over 3.6V (means over maximum operating voltage)
  39. int quality = 0; // Voltage range from 2,6V > 0% to 3,6V > 100%
  40. uint16_t voltage = ESP.getVcc();
  41. if (voltage <= 2600) {
  42. quality = 0;
  43. } else if (voltage >= 4600) {
  44. quality = 200;
  45. } else {
  46. quality = (voltage - 2600) / 10;
  47. }
  48. return quality;
  49. }
  50. int DomoticzRssiQuality(void)
  51. {
  52. // RSSI range: 0% to 10% (12 means disable RSSI in Domoticz)
  53. return WifiGetRssiAsQuality(WiFi.RSSI()) / 10;
  54. }
  55. void MqttPublishDomoticzFanState()
  56. {
  57. if (Settings.flag.mqtt_enabled && Settings.domoticz_relay_idx[1]) {
  58. char svalue[8]; // Fanspeed value
  59. int fan_speed = GetFanspeed();
  60. snprintf_P(svalue, sizeof(svalue), PSTR("%d"), fan_speed * 10);
  61. snprintf_P(mqtt_data, sizeof(mqtt_data), DOMOTICZ_MESSAGE,
  62. Settings.domoticz_relay_idx[1], (0 == fan_speed) ? 0 : 2, svalue, DomoticzBatteryQuality(), DomoticzRssiQuality());
  63. MqttPublish(domoticz_in_topic);
  64. fan_debounce = millis();
  65. }
  66. }
  67. void DomoticzUpdateFanState()
  68. {
  69. if (domoticz_update_flag) {
  70. MqttPublishDomoticzFanState();
  71. }
  72. domoticz_update_flag = 1;
  73. }
  74. void MqttPublishDomoticzPowerState(byte device)
  75. {
  76. if (Settings.flag.mqtt_enabled) {
  77. if ((device < 1) || (device > devices_present)) { device = 1; }
  78. if (Settings.domoticz_relay_idx[device -1]) {
  79. if ((SONOFF_IFAN02 == Settings.module) && (device > 1)) {
  80. // Fan handled by MqttPublishDomoticzFanState
  81. } else {
  82. char svalue[8]; // Dimmer value
  83. snprintf_P(svalue, sizeof(svalue), PSTR("%d"), Settings.light_dimmer);
  84. snprintf_P(mqtt_data, sizeof(mqtt_data), DOMOTICZ_MESSAGE,
  85. Settings.domoticz_relay_idx[device -1], (power & (1 << (device -1))) ? 1 : 0, (light_type) ? svalue : "", DomoticzBatteryQuality(), DomoticzRssiQuality());
  86. MqttPublish(domoticz_in_topic);
  87. }
  88. }
  89. }
  90. }
  91. void DomoticzUpdatePowerState(byte device)
  92. {
  93. if (domoticz_update_flag) {
  94. MqttPublishDomoticzPowerState(device);
  95. }
  96. domoticz_update_flag = 1;
  97. }
  98. void DomoticzMqttUpdate(void)
  99. {
  100. if (domoticz_subscribe && (Settings.domoticz_update_timer || domoticz_update_timer)) {
  101. domoticz_update_timer--;
  102. if (domoticz_update_timer <= 0) {
  103. domoticz_update_timer = Settings.domoticz_update_timer;
  104. for (byte i = 1; i <= devices_present; i++) {
  105. if ((SONOFF_IFAN02 == Settings.module) && (i > 1)) {
  106. MqttPublishDomoticzFanState();
  107. break;
  108. } else {
  109. MqttPublishDomoticzPowerState(i);
  110. }
  111. }
  112. }
  113. }
  114. }
  115. void DomoticzMqttSubscribe(void)
  116. {
  117. uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present;
  118. for (byte i = 0; i < maxdev; i++) {
  119. if (Settings.domoticz_relay_idx[i]) {
  120. domoticz_subscribe = true;
  121. }
  122. }
  123. if (domoticz_subscribe) {
  124. char stopic[TOPSZ];
  125. snprintf_P(stopic, sizeof(stopic), PSTR("%s/#"), domoticz_out_topic); // domoticz topic
  126. MqttSubscribe(stopic);
  127. }
  128. }
  129. /*
  130. * ArduinoJSON Domoticz Switch entry used to calculate jsonBuf: JSON_OBJECT_SIZE(11) + 129 = 313
  131. {
  132. "Battery" : 255,
  133. "RSSI" : 12,
  134. "dtype" : "Light/Switch",
  135. "id" : "000140E7",
  136. "idx" : 159,
  137. "name" : "Sonoff1",
  138. "nvalue" : 1,
  139. "stype" : "Switch",
  140. "svalue1" : "0",
  141. "switchType" : "Dimmer",
  142. "unit" : 1
  143. }
  144. * Fail on this one
  145. {
  146. "LastUpdate" : "2018-10-02 20:39:45",
  147. "Name" : "Sfeerverlichting",
  148. "Status" : "Off",
  149. "Timers" : "true",
  150. "Type" : "Group",
  151. "idx" : "2"
  152. }
  153. */
  154. boolean DomoticzMqttData(void)
  155. {
  156. char stemp1[10];
  157. unsigned long idx = 0;
  158. int16_t nvalue = -1;
  159. int16_t found = 0;
  160. domoticz_update_flag = 1;
  161. if (!strncmp(XdrvMailbox.topic, domoticz_out_topic, strlen(domoticz_out_topic))) {
  162. if (XdrvMailbox.data_len < 20) {
  163. return 1;
  164. }
  165. StaticJsonBuffer<400> jsonBuf;
  166. JsonObject& domoticz = jsonBuf.parseObject(XdrvMailbox.data);
  167. if (!domoticz.success()) {
  168. return 1;
  169. }
  170. // if (strcmp_P(domoticz["dtype"],PSTR("Light/Switch"))) {
  171. // return 1;
  172. // }
  173. idx = domoticz["idx"];
  174. if (domoticz.containsKey("nvalue")) {
  175. nvalue = domoticz["nvalue"];
  176. }
  177. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue);
  178. AddLog(LOG_LEVEL_DEBUG_MORE);
  179. if ((idx > 0) && (nvalue >= 0) && (nvalue <= 15)) {
  180. uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present;
  181. for (byte i = 0; i < maxdev; i++) {
  182. if (idx == Settings.domoticz_relay_idx[i]) {
  183. bool iscolordimmer = strcmp_P(domoticz["dtype"],PSTR("Color Switch")) == 0;
  184. snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1);
  185. if ((SONOFF_IFAN02 == Settings.module) && (1 == i)) { // Idx 2 is fanspeed
  186. uint8_t svalue = 0;
  187. if (domoticz.containsKey("svalue1")) {
  188. svalue = domoticz["svalue1"];
  189. } else {
  190. return 1;
  191. }
  192. svalue = (nvalue == 2) ? svalue / 10 : 0;
  193. if (GetFanspeed() == svalue) {
  194. return 1; // Stop loop as already set
  195. }
  196. if (TimePassedSince(fan_debounce) < 1000) {
  197. return 1; // Stop loop if device in limbo
  198. }
  199. snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_FANSPEED));
  200. snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), svalue);
  201. found = 1;
  202. }
  203. else if (iscolordimmer && 10 == nvalue) { // Color_SetColor
  204. JsonObject& color = domoticz["Color"];
  205. uint16_t level = nvalue = domoticz["svalue1"];
  206. uint16_t r = color["r"]; r = r * level / 100;
  207. uint16_t g = color["g"]; g = g * level / 100;
  208. uint16_t b = color["b"]; b = b * level / 100;
  209. uint16_t cw = color["cw"]; cw = cw * level / 100;
  210. uint16_t ww = color["ww"]; ww = ww * level / 100;
  211. snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_COLOR));
  212. snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%02x%02x%02x%02x%02x"), r, g, b, cw, ww);
  213. found = 1;
  214. }
  215. else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel
  216. (iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel
  217. if (domoticz.containsKey("svalue1")) {
  218. nvalue = domoticz["svalue1"];
  219. } else {
  220. return 1;
  221. }
  222. if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &1)) {
  223. return 1;
  224. }
  225. snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_DIMMER));
  226. snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
  227. found = 1;
  228. }
  229. else if (1 == nvalue || 0 == nvalue) {
  230. if (((power >> i) &1) == (power_t)nvalue) {
  231. return 1; // Stop loop
  232. }
  233. snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (devices_present > 1) ? stemp1 : "");
  234. snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
  235. found = 1;
  236. }
  237. break;
  238. }
  239. }
  240. }
  241. if (!found) {
  242. return 1;
  243. }
  244. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ D_RECEIVED_TOPIC " %s, " D_DATA " %s"), XdrvMailbox.topic, XdrvMailbox.data);
  245. AddLog(LOG_LEVEL_DEBUG_MORE);
  246. domoticz_update_flag = 0;
  247. }
  248. return 0;
  249. }
  250. /*********************************************************************************************\
  251. * Commands
  252. \*********************************************************************************************/
  253. boolean DomoticzCommand(void)
  254. {
  255. char command [CMDSZ];
  256. boolean serviced = true;
  257. uint8_t dmtcz_len = strlen(D_CMND_DOMOTICZ); // Prep for string length change
  258. if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_DOMOTICZ), dmtcz_len)) { // Prefix
  259. int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic +dmtcz_len, kDomoticzCommands);
  260. if (-1 == command_code) {
  261. serviced = false; // Unknown command
  262. }
  263. else if ((CMND_IDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) {
  264. if (XdrvMailbox.payload >= 0) {
  265. Settings.domoticz_relay_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
  266. restart_flag = 2;
  267. }
  268. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_relay_idx[XdrvMailbox.index -1]);
  269. }
  270. else if ((CMND_KEYIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) {
  271. if (XdrvMailbox.payload >= 0) {
  272. Settings.domoticz_key_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
  273. }
  274. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_LVALUE, command, XdrvMailbox.index, Settings.domoticz_key_idx[XdrvMailbox.index -1]);
  275. }
  276. else if ((CMND_SWITCHIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) {
  277. if (XdrvMailbox.payload >= 0) {
  278. Settings.domoticz_switch_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
  279. }
  280. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_switch_idx[XdrvMailbox.index -1]);
  281. }
  282. else if ((CMND_SENSORIDX == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= DZ_MAX_SENSORS)) {
  283. if (XdrvMailbox.payload >= 0) {
  284. Settings.domoticz_sensor_idx[XdrvMailbox.index -1] = XdrvMailbox.payload;
  285. }
  286. snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DOMOTICZ_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.domoticz_sensor_idx[XdrvMailbox.index -1]);
  287. }
  288. else if (CMND_UPDATETIMER == command_code) {
  289. if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
  290. Settings.domoticz_update_timer = XdrvMailbox.payload;
  291. }
  292. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_DOMOTICZ "%s\":%d}"), command, Settings.domoticz_update_timer);
  293. }
  294. else serviced = false; // Unknown command
  295. }
  296. else serviced = false; // Unknown command
  297. return serviced;
  298. }
  299. boolean DomoticzSendKey(byte key, byte device, byte state, byte svalflg)
  300. {
  301. boolean result = 0;
  302. if (device <= MAX_DOMOTICZ_IDX) {
  303. if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) {
  304. snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
  305. (key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (2 == state) ? "Toggle" : "On" : "Off");
  306. MqttPublish(domoticz_in_topic);
  307. result = 1;
  308. }
  309. }
  310. return result;
  311. }
  312. /*********************************************************************************************\
  313. * Sensors
  314. *
  315. * Source : https://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s
  316. * https://www.domoticz.com/wiki/MQTT
  317. *
  318. * Percentage, Barometric, Air Quality:
  319. * {\"idx\":%d,\"nvalue\":%s}, Idx, Value
  320. *
  321. * Humidity:
  322. * {\"idx\":%d,\"nvalue\":%s,\"svalue\":\"%s\"}, Idx, Humidity, HumidityStatus
  323. *
  324. * All other:
  325. * {\"idx\":%d,\"nvalue\":0,\"svalue\":\"%s\"}, Idx, Value(s)
  326. *
  327. \*********************************************************************************************/
  328. uint8_t DomoticzHumidityState(char *hum)
  329. {
  330. uint8_t h = atoi(hum);
  331. return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1;
  332. }
  333. void DomoticzSensor(byte idx, char *data)
  334. {
  335. if (Settings.domoticz_sensor_idx[idx]) {
  336. char dmess[90];
  337. memcpy(dmess, mqtt_data, sizeof(dmess));
  338. if (DZ_AIRQUALITY == idx) {
  339. snprintf_P(mqtt_data, sizeof(dmess), PSTR("{\"idx\":%d,\"nvalue\":%s,\"Battery\":%d,\"RSSI\":%d}"),
  340. Settings.domoticz_sensor_idx[idx], data, DomoticzBatteryQuality(), DomoticzRssiQuality());
  341. } else {
  342. snprintf_P(mqtt_data, sizeof(dmess), DOMOTICZ_MESSAGE,
  343. Settings.domoticz_sensor_idx[idx], 0, data, DomoticzBatteryQuality(), DomoticzRssiQuality());
  344. }
  345. MqttPublish(domoticz_in_topic);
  346. memcpy(mqtt_data, dmess, sizeof(dmess));
  347. }
  348. }
  349. void DomoticzSensor(byte idx, uint32_t value)
  350. {
  351. char data[16];
  352. snprintf_P(data, sizeof(data), PSTR("%d"), value);
  353. DomoticzSensor(idx, data);
  354. }
  355. void DomoticzTempHumSensor(char *temp, char *hum)
  356. {
  357. char data[16];
  358. snprintf_P(data, sizeof(data), PSTR("%s;%s;%d"), temp, hum, DomoticzHumidityState(hum));
  359. DomoticzSensor(DZ_TEMP_HUM, data);
  360. }
  361. void DomoticzTempHumPressureSensor(char *temp, char *hum, char *baro)
  362. {
  363. char data[32];
  364. snprintf_P(data, sizeof(data), PSTR("%s;%s;%d;%s;5"), temp, hum, DomoticzHumidityState(hum), baro);
  365. DomoticzSensor(DZ_TEMP_HUM_BARO, data);
  366. }
  367. void DomoticzSensorPowerEnergy(int power, char *energy)
  368. {
  369. char data[16];
  370. snprintf_P(data, sizeof(data), PSTR("%d;%s"), power, energy);
  371. DomoticzSensor(DZ_POWER_ENERGY, data);
  372. }
  373. /*********************************************************************************************\
  374. * Presentation
  375. \*********************************************************************************************/
  376. #ifdef USE_WEBSERVER
  377. #define WEB_HANDLE_DOMOTICZ "dm"
  378. const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ;
  379. const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM =
  380. "<br/><form action='" WEB_HANDLE_DOMOTICZ "' method='get'><button>" D_CONFIGURE_DOMOTICZ "</button></form>";
  381. const char HTTP_FORM_DOMOTICZ[] PROGMEM =
  382. "<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend><form method='post' action='" WEB_HANDLE_DOMOTICZ "'>"
  383. "<br/><table>";
  384. const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
  385. "<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " {1</b></td><td style='width:70px'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>"
  386. "<tr><td style='width:260px'><b>" D_DOMOTICZ_KEY_IDX " {1</b></td><td style='width:70px'><input id='k{1' name='k{1' placeholder='0' value='{3'></td></tr>";
  387. const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM =
  388. "<tr><td style='width:260px'><b>" D_DOMOTICZ_SWITCH_IDX " {1</b></td><td style='width:70px'><input id='s{1' name='s{1' placeholder='0' value='{4'></td></tr>";
  389. const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM =
  390. "<tr><td style='width:260px'><b>" D_DOMOTICZ_SENSOR_IDX " {1</b> {2</td><td style='width:70px'><input id='l{1' name='l{1' placeholder='0' value='{5'></td></tr>";
  391. const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM =
  392. "<tr><td style='width:260px'><b>" D_DOMOTICZ_UPDATE_TIMER "</b> (" STR(DOMOTICZ_UPDATE_TIMER) ")</td><td style='width:70px'><input id='ut' name='ut' placeholder='" STR(DOMOTICZ_UPDATE_TIMER) "' value='{6'</td></tr>";
  393. void HandleDomoticzConfiguration(void)
  394. {
  395. if (HttpUser()) { return; }
  396. if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
  397. AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ);
  398. if (WebServer->hasArg("save")) {
  399. DomoticzSaveSettings();
  400. WebRestart(1);
  401. return;
  402. }
  403. char stemp[32];
  404. String page = FPSTR(HTTP_HEAD);
  405. page.replace(F("{v}"), FPSTR(S_CONFIGURE_DOMOTICZ));
  406. page += FPSTR(HTTP_HEAD_STYLE);
  407. page += FPSTR(HTTP_FORM_DOMOTICZ);
  408. for (int i = 0; i < MAX_DOMOTICZ_IDX; i++) {
  409. if (i < devices_present) {
  410. page += FPSTR(HTTP_FORM_DOMOTICZ_RELAY);
  411. page.replace("{2", String((int)Settings.domoticz_relay_idx[i]));
  412. page.replace("{3", String((int)Settings.domoticz_key_idx[i]));
  413. }
  414. if (pin[GPIO_SWT1 +i] < 99) {
  415. page += FPSTR(HTTP_FORM_DOMOTICZ_SWITCH);
  416. page.replace("{4", String((int)Settings.domoticz_switch_idx[i]));
  417. }
  418. page.replace("{1", String(i +1));
  419. if ((SONOFF_IFAN02 == Settings.module) && (1 == i)) { break; }
  420. }
  421. for (int i = 0; i < DZ_MAX_SENSORS; i++) {
  422. page += FPSTR(HTTP_FORM_DOMOTICZ_SENSOR);
  423. page.replace("{1", String(i +1));
  424. page.replace("{2", GetTextIndexed(stemp, sizeof(stemp), i, kDomoticzSensors));
  425. page.replace("{5", String((int)Settings.domoticz_sensor_idx[i]));
  426. }
  427. page += FPSTR(HTTP_FORM_DOMOTICZ_TIMER);
  428. page.replace("{6", String((int)Settings.domoticz_update_timer));
  429. page += F("</table>");
  430. page += FPSTR(HTTP_FORM_END);
  431. page += FPSTR(HTTP_BTN_CONF);
  432. ShowPage(page);
  433. }
  434. void DomoticzSaveSettings(void)
  435. {
  436. char stemp[20];
  437. char ssensor_indices[6 * MAX_DOMOTICZ_SNS_IDX];
  438. char tmp[100];
  439. for (byte i = 0; i < MAX_DOMOTICZ_IDX; i++) {
  440. snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i +1);
  441. WebGetArg(stemp, tmp, sizeof(tmp));
  442. Settings.domoticz_relay_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
  443. snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i +1);
  444. WebGetArg(stemp, tmp, sizeof(tmp));
  445. Settings.domoticz_key_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
  446. snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i +1);
  447. WebGetArg(stemp, tmp, sizeof(tmp));
  448. Settings.domoticz_switch_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
  449. }
  450. ssensor_indices[0] = '\0';
  451. for (byte i = 0; i < DZ_MAX_SENSORS; i++) {
  452. snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i +1);
  453. WebGetArg(stemp, tmp, sizeof(tmp));
  454. Settings.domoticz_sensor_idx[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
  455. snprintf_P(ssensor_indices, sizeof(ssensor_indices), PSTR("%s%s%d"), ssensor_indices, (strlen(ssensor_indices)) ? "," : "", Settings.domoticz_sensor_idx[i]);
  456. }
  457. WebGetArg("ut", tmp, sizeof(tmp));
  458. Settings.domoticz_update_timer = (!strlen(tmp)) ? DOMOTICZ_UPDATE_TIMER : atoi(tmp);
  459. snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ D_CMND_IDX " %d,%d,%d,%d, " D_CMND_KEYIDX " %d,%d,%d,%d, " D_CMND_SWITCHIDX " %d,%d,%d,%d, " D_CMND_SENSORIDX " %s, " D_CMND_UPDATETIMER " %d"),
  460. Settings.domoticz_relay_idx[0], Settings.domoticz_relay_idx[1], Settings.domoticz_relay_idx[2], Settings.domoticz_relay_idx[3],
  461. Settings.domoticz_key_idx[0], Settings.domoticz_key_idx[1], Settings.domoticz_key_idx[2], Settings.domoticz_key_idx[3],
  462. Settings.domoticz_switch_idx[0], Settings.domoticz_switch_idx[1], Settings.domoticz_switch_idx[2], Settings.domoticz_switch_idx[3],
  463. ssensor_indices, Settings.domoticz_update_timer);
  464. AddLog(LOG_LEVEL_INFO);
  465. }
  466. #endif // USE_WEBSERVER
  467. /*********************************************************************************************\
  468. * Interface
  469. \*********************************************************************************************/
  470. boolean Xdrv07(byte function)
  471. {
  472. boolean result = false;
  473. if (Settings.flag.mqtt_enabled) {
  474. switch (function) {
  475. #ifdef USE_WEBSERVER
  476. case FUNC_WEB_ADD_BUTTON:
  477. strncat_P(mqtt_data, HTTP_BTN_MENU_DOMOTICZ, sizeof(mqtt_data) - strlen(mqtt_data) -1);
  478. break;
  479. case FUNC_WEB_ADD_HANDLER:
  480. WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration);
  481. break;
  482. #endif // USE_WEBSERVER
  483. case FUNC_COMMAND:
  484. result = DomoticzCommand();
  485. break;
  486. case FUNC_MQTT_SUBSCRIBE:
  487. DomoticzMqttSubscribe();
  488. break;
  489. case FUNC_MQTT_INIT:
  490. domoticz_update_timer = 2;
  491. break;
  492. case FUNC_MQTT_DATA:
  493. result = DomoticzMqttData();
  494. break;
  495. case FUNC_EVERY_SECOND:
  496. DomoticzMqttUpdate();
  497. break;
  498. case FUNC_SHOW_SENSOR:
  499. // DomoticzSendSensor();
  500. break;
  501. }
  502. }
  503. return result;
  504. }
  505. #endif // USE_DOMOTICZ