"
29 | "In topic (" DOMOTICZ_IN_TOPIC ") | |
"
30 | "Out topic (" DOMOTICZ_OUT_TOPIC ") | |
";
31 | const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
32 | "Idx {1 | |
"
33 | "Key idx {1 | |
";
34 | const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM =
35 | "Switch idx {1 | |
";
36 | const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM =
37 | "Sensor idx {1 - {2 | |
";
38 | const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM =
39 | "Update timer (" STR(DOMOTICZ_UPDATE_TIMER) ") | |
";
40 | #endif // USE_WEBSERVER
41 |
42 | const char domoticz_sensors[DOMOTICZ_MAX_SENSORS][14] PROGMEM =
43 | { "Temp", "Temp,Hum", "Temp,Hum,Baro", "Power,Energy", "Illuminance" };
44 |
45 | int domoticz_update_timer = 0;
46 | byte domoticz_update_flag = 1;
47 |
48 | void mqtt_publishDomoticzPowerState(byte device)
49 | {
50 | char svalue[64]; // was MESSZ
51 |
52 | if (sysCfg.domoticz_relay_idx[device -1] && (strlen(sysCfg.domoticz_in_topic) != 0)) {
53 | if ((device < 1) || (device > Maxdevice)) {
54 | device = 1;
55 | }
56 |
57 | if (SONOFF_LED == sysCfg.module) {
58 | snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":2,\"svalue\":\"%d\"}"),
59 | sysCfg.domoticz_relay_idx[device -1], sysCfg.led_dimmer[device -1]);
60 | mqtt_publish(sysCfg.domoticz_in_topic, svalue);
61 | }
62 | else if ((1 == device) && (pin[GPIO_WS2812] < 99)) {
63 | snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":2,\"svalue\":\"%d\"}"),
64 | sysCfg.domoticz_relay_idx[device -1], sysCfg.ws_dimmer);
65 | mqtt_publish(sysCfg.domoticz_in_topic, svalue);
66 | }
67 | snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"\"}"),
68 | sysCfg.domoticz_relay_idx[device -1], (power & (0x01 << (device -1))) ? 1 : 0);
69 | mqtt_publish(sysCfg.domoticz_in_topic, svalue);
70 | }
71 | }
72 |
73 | void domoticz_updatePowerState(byte device)
74 | {
75 | if (domoticz_update_flag) {
76 | mqtt_publishDomoticzPowerState(device);
77 | }
78 | domoticz_update_flag = 1;
79 | }
80 |
81 | void domoticz_mqttUpdate()
82 | {
83 | if ((sysCfg.domoticz_update_timer || domoticz_update_timer) && sysCfg.domoticz_relay_idx[0]) {
84 | domoticz_update_timer--;
85 | if (domoticz_update_timer <= 0) {
86 | domoticz_update_timer = sysCfg.domoticz_update_timer;
87 | for (byte i = 1; i <= Maxdevice; i++) {
88 | mqtt_publishDomoticzPowerState(i);
89 | }
90 | }
91 | }
92 | }
93 |
94 | void domoticz_setUpdateTimer(uint16_t value)
95 | {
96 | domoticz_update_timer = value;
97 | }
98 |
99 | void domoticz_mqttSubscribe()
100 | {
101 | if (sysCfg.domoticz_relay_idx[0] && (strlen(sysCfg.domoticz_out_topic) != 0)) {
102 | char stopic[TOPSZ];
103 | snprintf_P(stopic, sizeof(stopic), PSTR("%s/#"), sysCfg.domoticz_out_topic); // domoticz topic
104 | mqttClient.subscribe(stopic);
105 | mqttClient.loop(); // Solve LmacRxBlk:1 messages
106 | }
107 | }
108 |
109 | boolean domoticz_update()
110 | {
111 | return domoticz_update_flag;
112 | }
113 |
114 | /*
115 | * ArduinoJSON Domoticz Switch entry used to calculate jsonBuf: JSON_OBJECT_SIZE(11) + 129 = 313
116 | {
117 | "Battery" : 255,
118 | "RSSI" : 12,
119 | "dtype" : "Light/Switch",
120 | "id" : "000140E7",
121 | "idx" : 159,
122 | "name" : "Sonoff1",
123 | "nvalue" : 1,
124 | "stype" : "Switch",
125 | "svalue1" : "0",
126 | "switchType" : "Dimmer",
127 | "unit" : 1
128 | }
129 | */
130 |
131 | boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t sdataBuf)
132 | {
133 | char log[LOGSZ];
134 | char stemp1[10];
135 | char scommand[10];
136 | unsigned long idx = 0;
137 | int16_t nvalue;
138 | int16_t found = 0;
139 |
140 | domoticz_update_flag = 1;
141 | if (!strncmp(topicBuf, sysCfg.domoticz_out_topic, strlen(sysCfg.domoticz_out_topic)) != 0) {
142 | if (sdataBuf < 20) {
143 | return 1;
144 | }
145 | StaticJsonBuffer<400> jsonBuf;
146 | JsonObject& domoticz = jsonBuf.parseObject(dataBuf);
147 | if (!domoticz.success()) {
148 | return 1;
149 | }
150 | // if (strcmp_P(domoticz["dtype"],PSTR("Light/Switch"))) {
151 | // return 1;
152 | // }
153 | idx = domoticz["idx"];
154 | nvalue = domoticz["nvalue"];
155 |
156 | snprintf_P(log, sizeof(log), PSTR("DMTZ: idx %d, nvalue %d"), idx, nvalue);
157 | addLog(LOG_LEVEL_DEBUG_MORE, log);
158 |
159 | if (nvalue >= 0 && nvalue <= 2) {
160 | for (byte i = 0; i < Maxdevice; i++) {
161 | if ((idx > 0) && (idx == sysCfg.domoticz_relay_idx[i])) {
162 | snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1);
163 | if (2 == nvalue) {
164 | nvalue = domoticz["svalue1"];
165 | if ((pin[GPIO_WS2812] < 99) && (sysCfg.ws_dimmer == nvalue)) {
166 | return 1;
167 | }
168 | if ((SONOFF_LED == sysCfg.module) && (sysCfg.led_dimmer[i] == nvalue)) {
169 | return 1;
170 | }
171 | snprintf_P(topicBuf, stopicBuf, PSTR("/DIMMER%s"), (Maxdevice > 1) ? stemp1 : "");
172 | snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue);
173 | found = 1;
174 | } else {
175 | if (((power >> i) &1) == nvalue) {
176 | return 1;
177 | }
178 | snprintf_P(topicBuf, stopicBuf, PSTR("/POWER%s"), (Maxdevice > 1) ? stemp1 : "");
179 | snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue);
180 | found = 1;
181 | }
182 | break;
183 | }
184 | }
185 | }
186 | if (!found) {
187 | return 1;
188 | }
189 |
190 | snprintf_P(log, sizeof(log), PSTR("DMTZ: Receive topic %s, data %s"), topicBuf, dataBuf);
191 | addLog(LOG_LEVEL_DEBUG_MORE, log);
192 |
193 | domoticz_update_flag = 0;
194 | }
195 | return 0;
196 | }
197 |
198 | /*********************************************************************************************\
199 | * Commands
200 | \*********************************************************************************************/
201 |
202 | boolean domoticz_command(const char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
203 | {
204 | boolean serviced = true;
205 |
206 | if (!strncmp_P(type,PSTR("DOMOTICZ"),8)) {
207 | if (!strcmp_P(type +8,PSTR("INTOPIC"))) {
208 | if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_in_topic))) {
209 | strlcpy(sysCfg.domoticz_in_topic, (1 == payload) ? DOMOTICZ_IN_TOPIC : dataBuf, sizeof(sysCfg.domoticz_in_topic));
210 | restartflag = 2;
211 | }
212 | snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzInTopic\":\"%s\"}"), sysCfg.domoticz_in_topic);
213 | }
214 | else if (!strcmp_P(type +8,PSTR("OUTTOPIC"))) {
215 | if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_out_topic))) {
216 | strlcpy(sysCfg.domoticz_out_topic, (1 == payload) ? DOMOTICZ_OUT_TOPIC : dataBuf, sizeof(sysCfg.domoticz_out_topic));
217 | restartflag = 2;
218 | }
219 | snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzOutTopic\":\"%s\"}"), sysCfg.domoticz_out_topic);
220 | }
221 | else if (!strcmp_P(type +8,PSTR("IDX")) && (index > 0) && (index <= Maxdevice)) {
222 | if ((data_len > 0) && (payload >= 0)) {
223 | sysCfg.domoticz_relay_idx[index -1] = payload;
224 | restartflag = 2;
225 | }
226 | snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzIdx%d\":%d}"), index, sysCfg.domoticz_relay_idx[index -1]);
227 | }
228 | else if (!strcmp_P(type +8,PSTR("KEYIDX")) && (index > 0) && (index <= Maxdevice)) {
229 | if ((data_len > 0) && (payload >= 0)) {
230 | sysCfg.domoticz_key_idx[index -1] = payload;
231 | }
232 | snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzKeyIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]);
233 | }
234 | else if (!strcmp_P(type +8,PSTR("SWITCHIDX")) && (index > 0) && (index <= Maxdevice)) {
235 | if ((data_len > 0) && (payload >= 0)) {
236 | sysCfg.domoticz_switch_idx[index -1] = payload;
237 | }
238 | snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSwitchIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]);
239 | }
240 | else if (!strcmp_P(type +8,PSTR("SENSORIDX")) && (index > 0) && (index <= DOMOTICZ_MAX_SENSORS)) {
241 | if ((data_len > 0) && (payload >= 0)) {
242 | sysCfg.domoticz_sensor_idx[index -1] = payload;
243 | }
244 | snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSensorIdx%d\":%d}"), index, sysCfg.domoticz_sensor_idx[index -1]);
245 | }
246 | else if (!strcmp_P(type +8,PSTR("UPDATETIMER"))) {
247 | if ((data_len > 0) && (payload >= 0) && (payload < 3601)) {
248 | sysCfg.domoticz_update_timer = payload;
249 | }
250 | snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzUpdateTimer\":%d}"), sysCfg.domoticz_update_timer);
251 | }
252 | else serviced = false;
253 | }
254 | else serviced = false;
255 | return serviced;
256 | }
257 |
258 | boolean domoticz_button(byte key, byte device, byte state, byte svalflg)
259 | {
260 | if ((sysCfg.domoticz_key_idx[device -1] || sysCfg.domoticz_switch_idx[device -1]) && (svalflg)) {
261 | char svalue[80]; // was MESSZ
262 |
263 | snprintf_P(svalue, sizeof(svalue), PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"),
264 | (key) ? sysCfg.domoticz_switch_idx[device -1] : sysCfg.domoticz_key_idx[device -1], (state) ? (2 == state) ? "Toggle" : "On" : "Off");
265 | mqtt_publish(sysCfg.domoticz_in_topic, svalue);
266 | return 1;
267 | } else {
268 | return 0;
269 | }
270 | }
271 |
272 | /*********************************************************************************************\
273 | * Sensors
274 | \*********************************************************************************************/
275 |
276 | uint8_t dom_hum_stat(char *hum)
277 | {
278 | uint8_t h = atoi(hum);
279 | return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1;
280 | }
281 |
282 | void dom_sensor(byte idx, char *data)
283 | {
284 | char dmess[64];
285 |
286 | if (sysCfg.domoticz_sensor_idx[idx] && (strlen(sysCfg.domoticz_in_topic) != 0)) {
287 | snprintf_P(dmess, sizeof(dmess), PSTR("{\"idx\":%d,\"nvalue\":0,\"svalue\":\"%s\"}"),
288 | sysCfg.domoticz_sensor_idx[idx], data);
289 | mqtt_publish(sysCfg.domoticz_in_topic, dmess);
290 | }
291 | }
292 |
293 | void domoticz_sensor1(char *temp)
294 | {
295 | dom_sensor(0, temp);
296 | }
297 |
298 | void domoticz_sensor2(char *temp, char *hum)
299 | {
300 | char data[16];
301 | snprintf_P(data, sizeof(data), PSTR("%s;%s;%d"), temp, hum, dom_hum_stat(hum));
302 | dom_sensor(1, data);
303 | }
304 |
305 | void domoticz_sensor3(char *temp, char *hum, char *baro)
306 | {
307 | char data[32];
308 | snprintf_P(data, sizeof(data), PSTR("%s;%s;%d;%s;5"), temp, hum, dom_hum_stat(hum), baro);
309 | dom_sensor(2, data);
310 | }
311 |
312 | void domoticz_sensor4(uint16_t power, char *energy)
313 | {
314 | char data[16];
315 | snprintf_P(data, sizeof(data), PSTR("%d;%s"), power, energy);
316 | dom_sensor(3, data);
317 | }
318 |
319 | void domoticz_sensor5(uint16_t lux)
320 | {
321 | char data[8];
322 | snprintf_P(data, sizeof(data), PSTR("%d"), lux);
323 | dom_sensor(4, data);
324 | }
325 |
326 | /*********************************************************************************************\
327 | * Presentation
328 | \*********************************************************************************************/
329 |
330 | #ifdef USE_WEBSERVER
331 | void handleDomoticz()
332 | {
333 | if (HTTP_USER == _httpflag) {
334 | handleRoot();
335 | return;
336 | }
337 | addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Domoticz config"));
338 |
339 | char stemp[20];
340 |
341 | String page = FPSTR(HTTP_HEAD);
342 | page.replace("{v}", "Configure Domoticz");
343 | page += FPSTR(HTTP_FORM_DOMOTICZ);
344 | page.replace("{d1}", String(sysCfg.domoticz_in_topic));
345 | page.replace("{d2}", String(sysCfg.domoticz_out_topic));
346 | for (int i = 0; i < 4; i++) {
347 | if (i < Maxdevice) {
348 | page += FPSTR(HTTP_FORM_DOMOTICZ_RELAY);
349 | page.replace("{2", String((int)sysCfg.domoticz_relay_idx[i]));
350 | page.replace("{3", String((int)sysCfg.domoticz_key_idx[i]));
351 | }
352 | if (pin[GPIO_SWT1 +i] < 99) {
353 | page += FPSTR(HTTP_FORM_DOMOTICZ_SWITCH);
354 | page.replace("{4", String((int)sysCfg.domoticz_switch_idx[i]));
355 | }
356 | page.replace("{1", String(i +1));
357 | }
358 | for (int i = 0; i < DOMOTICZ_MAX_SENSORS; i++) {
359 | page += FPSTR(HTTP_FORM_DOMOTICZ_SENSOR);
360 | page.replace("{1", String(i +1));
361 | snprintf_P(stemp, sizeof(stemp), domoticz_sensors[i]);
362 | page.replace("{2", stemp);
363 | page.replace("{5", String((int)sysCfg.domoticz_sensor_idx[i]));
364 | }
365 | page += FPSTR(HTTP_FORM_DOMOTICZ_TIMER);
366 | page.replace("{6", String((int)sysCfg.domoticz_update_timer));
367 | page += F("
");
368 | page += FPSTR(HTTP_FORM_END);
369 | page += FPSTR(HTTP_BTN_CONF);
370 | showPage(page);
371 | }
372 |
373 | void domoticz_saveSettings()
374 | {
375 | char log[LOGSZ], stemp[20];
376 |
377 | strlcpy(sysCfg.domoticz_in_topic, (!strlen(webServer->arg("it").c_str())) ? DOMOTICZ_IN_TOPIC : webServer->arg("it").c_str(), sizeof(sysCfg.domoticz_in_topic));
378 | strlcpy(sysCfg.domoticz_out_topic, (!strlen(webServer->arg("ot").c_str())) ? DOMOTICZ_OUT_TOPIC : webServer->arg("ot").c_str(), sizeof(sysCfg.domoticz_out_topic));
379 | for (byte i = 0; i < 4; i++) {
380 | snprintf_P(stemp, sizeof(stemp), PSTR("r%d"), i +1);
381 | sysCfg.domoticz_relay_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
382 | snprintf_P(stemp, sizeof(stemp), PSTR("k%d"), i +1);
383 | sysCfg.domoticz_key_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
384 | snprintf_P(stemp, sizeof(stemp), PSTR("s%d"), i +1);
385 | sysCfg.domoticz_switch_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
386 | }
387 | for (byte i = 0; i < DOMOTICZ_MAX_SENSORS; i++) {
388 | snprintf_P(stemp, sizeof(stemp), PSTR("l%d"), i +1);
389 | sysCfg.domoticz_sensor_idx[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
390 | }
391 | sysCfg.domoticz_update_timer = (!strlen(webServer->arg("ut").c_str())) ? DOMOTICZ_UPDATE_TIMER : atoi(webServer->arg("ut").c_str());
392 | snprintf_P(log, sizeof(log), PSTR("HTTP: Domoticz in %s, out %s, idx %d, %d, %d, %d, update timer %d"),
393 | sysCfg.domoticz_in_topic, sysCfg.domoticz_out_topic,
394 | sysCfg.domoticz_relay_idx[0], sysCfg.domoticz_relay_idx[1], sysCfg.domoticz_relay_idx[2], sysCfg.domoticz_relay_idx[3],
395 | sysCfg.domoticz_update_timer);
396 | addLog(LOG_LEVEL_INFO, log);
397 | snprintf_P(log, sizeof(log), PSTR("HTTP: key %d, %d, %d, %d, switch %d, %d, %d, %d, sensor %d, %d, %d, %d, %d"),
398 | sysCfg.domoticz_key_idx[0], sysCfg.domoticz_key_idx[1], sysCfg.domoticz_key_idx[2], sysCfg.domoticz_key_idx[3],
399 | sysCfg.domoticz_switch_idx[0], sysCfg.domoticz_switch_idx[1], sysCfg.domoticz_switch_idx[2], sysCfg.domoticz_switch_idx[3],
400 | sysCfg.domoticz_sensor_idx[0], sysCfg.domoticz_sensor_idx[1], sysCfg.domoticz_sensor_idx[2], sysCfg.domoticz_sensor_idx[3], sysCfg.domoticz_sensor_idx[4]);
401 | addLog(LOG_LEVEL_INFO, log);
402 | }
403 | #endif // USE_WEBSERVER
404 | #endif // USE_DOMOTICZ
405 |
406 |
--------------------------------------------------------------------------------
/sonoff/xdrv_ir_send.ino:
--------------------------------------------------------------------------------
1 | /*
2 | xdrv_ir_send.ino - infra red support for Sonoff-Tasmota
3 |
4 | Copyright (C) 2017 Heiko Krupp and Theo Arends
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see