10
10
*/
11
11
/*
12
12
* @title Espalexa library
13
- * @version 2.4.5
13
+ * @version 2.4.6
14
14
* @author Christian Schwinne
15
15
* @license MIT
16
16
* @contributors d-999
49
49
#include < WiFiUdp.h>
50
50
51
51
#ifdef ESPALEXA_DEBUG
52
- #pragma message "Espalexa 2.4.5 debug mode"
52
+ #pragma message "Espalexa 2.4.6 debug mode"
53
53
#define EA_DEBUG (x ) Serial.print (x)
54
54
#define EA_DEBUGLN (x ) Serial.println (x)
55
55
#else
@@ -81,35 +81,29 @@ class Espalexa {
81
81
WiFiUDP espalexaUdp;
82
82
IPAddress ipMulti;
83
83
bool udpConnected = false ;
84
- char packetBuffer[255 ]; // buffer to hold incoming udp packet
85
84
String escapedMac=" " ; // lowercase mac address
86
85
87
86
// private member functions
88
- String boolString (bool st)
89
- {
90
- return (st)?" true" :" false" ;
91
- }
92
-
93
- String modeString (EspalexaColorMode m)
87
+ const char * modeString (EspalexaColorMode m)
94
88
{
95
89
if (m == EspalexaColorMode::xy) return " xy" ;
96
90
if (m == EspalexaColorMode::hs) return " hs" ;
97
91
return " ct" ;
98
92
}
99
93
100
- String typeString (EspalexaDeviceType t)
94
+ const char * typeString (EspalexaDeviceType t)
101
95
{
102
96
switch (t)
103
97
{
104
- case EspalexaDeviceType::dimmable: return " Dimmable light" ;
105
- case EspalexaDeviceType::whitespectrum: return " Color temperature light" ;
106
- case EspalexaDeviceType::color: return " Color light" ;
107
- case EspalexaDeviceType::extendedcolor: return " Extended color light" ;
98
+ case EspalexaDeviceType::dimmable: return PSTR ( " Dimmable light" ) ;
99
+ case EspalexaDeviceType::whitespectrum: return PSTR ( " Color temperature light" ) ;
100
+ case EspalexaDeviceType::color: return PSTR ( " Color light" ) ;
101
+ case EspalexaDeviceType::extendedcolor: return PSTR ( " Extended color light" ) ;
108
102
}
109
- return " Light " ;
103
+ return " " ;
110
104
}
111
105
112
- String modelidString (EspalexaDeviceType t)
106
+ const char * modelidString (EspalexaDeviceType t)
113
107
{
114
108
switch (t)
115
109
{
@@ -118,7 +112,7 @@ class Espalexa {
118
112
case EspalexaDeviceType::color: return " LST001" ;
119
113
case EspalexaDeviceType::extendedcolor: return " LCT015" ;
120
114
}
121
- return " Plug " ;
115
+ return " " ;
122
116
}
123
117
124
118
// Workaround functions courtesy of Sonoff-Tasmota
@@ -135,38 +129,38 @@ class Espalexa {
135
129
}
136
130
137
131
// device JSON string: color+temperature device emulates LCT015, dimmable device LWB010, (TODO: on/off Plug 01, color temperature device LWT010, color device LST001)
138
- String deviceJsonString (uint8_t deviceId)
132
+ void deviceJsonString (uint8_t deviceId, char * buf )
139
133
{
140
134
deviceId--;
141
- if (deviceId >= currentDeviceCount) return " {}" ; // error
135
+ if (deviceId >= currentDeviceCount) { strcpy (buf, " {}" ); return ;} // error
142
136
EspalexaDevice* dev = devices[deviceId];
143
-
144
- String json = " {\" state\" :{\" on\" :" ;
145
- json += boolString (dev->getValue ());
146
- if (dev->getType () != EspalexaDeviceType::onoff) // bri support
147
- {
148
- json += " ,\" bri\" :" + String (dev->getLastValue ()-1 );
149
- if (static_cast <uint8_t >(dev->getType ()) > 2 ) // color support
150
- {
151
- json += " ,\" hue\" :" + String (dev->getHue ()) + " ,\" sat\" :" + String (dev->getSat ());
152
- json += " ,\" effect\" :\" none\" ,\" xy\" :[" + String (dev->getX ()) + " ," + String (dev->getY ()) + " ]" ;
153
- }
154
- if (static_cast <uint8_t >(dev->getType ()) > 1 && dev->getType () != EspalexaDeviceType::color) // white spectrum support
155
- {
156
- json += " ,\" ct\" :" + String (dev->getCt ());
157
- }
158
- }
159
- json += " ,\" alert\" :\" none" ;
160
- if (static_cast <uint8_t >(dev->getType ()) > 1 ) json += " \" ,\" colormode\" :\" " + modeString (dev->getColorMode ());
161
- json += " \" ,\" mode\" :\" homeautomation\" ,\" reachable\" :true}," ;
162
- json += " \" type\" :\" " + typeString (dev->getType ());
163
- json += " \" ,\" name\" :\" " + dev->getName ();
164
- json += " \" ,\" modelid\" :\" " + modelidString (dev->getType ());
165
- json += " \" ,\" manufacturername\" :\" Philips\" ,\" productname\" :\" E" + String (static_cast <uint8_t >(dev->getType ()));
166
- json += " \" ,\" uniqueid\" :\" " + String (encodeLightId (deviceId+1 ));
167
- json += " \" ,\" swversion\" :\" espalexa-2.4.5\" }" ;
168
137
169
- return json;
138
+ // char buf_bri[12] = "";
139
+ // brightness support, add "bri" to JSON
140
+ // if (dev->getType() != EspalexaDeviceType::onoff)
141
+ // sprintf(buf_bri,",\"bri\":%u", dev->getLastValue()-1);
142
+
143
+ char buf_col[80 ] = " " ;
144
+ // color support
145
+ if (static_cast <uint8_t >(dev->getType ()) > 2 )
146
+ sprintf_P (buf_col,PSTR (" ,\" hue\" :%u,\" sat\" :%u,\" effect\" :\" none\" ,\" xy\" :[%f,%f]" )
147
+ ,dev->getHue (), dev->getSat (), dev->getX (), dev->getY ());
148
+
149
+ char buf_ct[16 ] = " " ;
150
+ // white spectrum support
151
+ if (static_cast <uint8_t >(dev->getType ()) > 1 && dev->getType () != EspalexaDeviceType::color)
152
+ sprintf (buf_ct, " ,\" ct\" :%u" , dev->getCt ());
153
+
154
+ char buf_cm[20 ] = " " ;
155
+ if (static_cast <uint8_t >(dev->getType ()) > 1 )
156
+ sprintf (buf_cm,PSTR (" \" ,\" colormode\" :\" %s" ), modeString (dev->getColorMode ()));
157
+
158
+ sprintf_P (buf, PSTR (" {\" state\" :{\" on\" :%s,\" bri\" :%u%s%s,\" alert\" :\" none%s\" ,\" mode\" :\" homeautomation\" ,\" reachable\" :true},"
159
+ " \" type\" :\" %s\" ,\" name\" :\" %s\" ,\" modelid\" :\" %s\" ,\" manufacturername\" :\" Philips\" ,\" productname\" :\" E%u"
160
+ " \" ,\" uniqueid\" :\" %u\" ,\" swversion\" :\" espalexa-2.4.6\" }" )
161
+
162
+ , (dev->getValue ())?" true" :" false" , dev->getLastValue ()-1 , buf_col, buf_ct, buf_cm, typeString (dev->getType ()),
163
+ dev->getName ().c_str (), modelidString (dev->getType ()), static_cast <uint8_t >(dev->getType ()), encodeLightId (deviceId+1 ));
170
164
}
171
165
172
166
// Espalexa status page /espalexa
@@ -181,14 +175,14 @@ class Espalexa {
181
175
res += " Value of device " + String (i+1 ) + " (" + dev->getName () + " ): " + String (dev->getValue ()) + " (" + typeString (dev->getType ());
182
176
if (static_cast <uint8_t >(dev->getType ()) > 1 ) // color support
183
177
{
184
- res += " , colormode=" + modeString (dev->getColorMode ()) + " , r=" + String (dev->getR ()) + " , g=" + String (dev->getG ()) + " , b=" + String (dev->getB ());
178
+ res += " , colormode=" + String ( modeString (dev->getColorMode () )) + " , r=" + String (dev->getR ()) + " , g=" + String (dev->getG ()) + " , b=" + String (dev->getB ());
185
179
res +=" , ct=" + String (dev->getCt ()) + " , hue=" + String (dev->getHue ()) + " , sat=" + String (dev->getSat ()) + " , x=" + String (dev->getX ()) + " , y=" + String (dev->getY ());
186
180
}
187
181
res += " )\r\n " ;
188
182
}
189
183
res += " \r\n Free Heap: " + (String)ESP.getFreeHeap ();
190
184
res += " \r\n Uptime: " + (String)millis ();
191
- res += " \r\n\r\n Espalexa library v2.4.5 by Christian Schwinne 2020" ;
185
+ res += " \r\n\r\n Espalexa library v2.4.6 by Christian Schwinne 2020" ;
192
186
server->send (200 , " text/plain" , res);
193
187
}
194
188
#endif
@@ -206,7 +200,7 @@ class Espalexa {
206
200
EA_DEBUGLN (" Body: " + body);
207
201
if (!handleAlexaApiCall (server))
208
202
#endif
209
- server->send (404 , " text/plain" , " Not Found (espalexa-internal )" );
203
+ server->send (404 , " text/plain" , " Not Found (espalexa)" );
210
204
}
211
205
212
206
// send description.xml device property page
@@ -216,30 +210,31 @@ class Espalexa {
216
210
IPAddress localIP = WiFi.localIP ();
217
211
char s[16 ];
218
212
sprintf (s, " %d.%d.%d.%d" , localIP[0 ], localIP[1 ], localIP[2 ], localIP[3 ]);
219
-
220
- String setup_xml = " <?xml version=\" 1.0\" ?>"
213
+ char buf[1024 ];
214
+
215
+ sprintf_P (buf,PSTR (" <?xml version=\" 1.0\" ?>"
221
216
" <root xmlns=\" urn:schemas-upnp-org:device-1-0\" >"
222
217
" <specVersion><major>1</major><minor>0</minor></specVersion>"
223
- " <URLBase>http://" + String (s) + " :80/</URLBase>"
218
+ " <URLBase>http://%s :80/</URLBase>"
224
219
" <device>"
225
220
" <deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
226
- " <friendlyName>Espalexa (" + String (s) + " )</friendlyName>"
221
+ " <friendlyName>Espalexa (%s )</friendlyName>"
227
222
" <manufacturer>Royal Philips Electronics</manufacturer>"
228
223
" <manufacturerURL>http://www.philips.com</manufacturerURL>"
229
224
" <modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
230
225
" <modelName>Philips hue bridge 2012</modelName>"
231
226
" <modelNumber>929000226503</modelNumber>"
232
227
" <modelURL>http://www.meethue.com</modelURL>"
233
- " <serialNumber>" + escapedMac + " </serialNumber>"
234
- " <UDN>uuid:2f402f80-da50-11e1-9b23-" + escapedMac + " </UDN>"
228
+ " <serialNumber>%s </serialNumber>"
229
+ " <UDN>uuid:2f402f80-da50-11e1-9b23-%s </UDN>"
235
230
" <presentationURL>index.html</presentationURL>"
236
231
" </device>"
237
- " </root>" ;
232
+ " </root>" ),s,s,escapedMac. c_str (),escapedMac. c_str ()) ;
238
233
239
- server->send (200 , " text/xml" , setup_xml. c_str () );
234
+ server->send (200 , " text/xml" , buf );
240
235
241
- EA_DEBUG (" Sending : " );
242
- EA_DEBUGLN (setup_xml);
236
+ EA_DEBUG (" Send setup.xml " );
237
+ // EA_DEBUGLN(setup_xml);
243
238
}
244
239
245
240
// init the server
@@ -290,22 +285,23 @@ class Espalexa {
290
285
char s[16 ];
291
286
sprintf (s, " %d.%d.%d.%d" , localIP[0 ], localIP[1 ], localIP[2 ], localIP[3 ]);
292
287
293
- String response =
294
- " HTTP/1.1 200 OK\r\n "
288
+ char buf[1024 ];
289
+
290
+ sprintf_P (buf,PSTR (" HTTP/1.1 200 OK\r\n "
295
291
" EXT:\r\n "
296
292
" CACHE-CONTROL: max-age=100\r\n " // SSDP_INTERVAL
297
- " LOCATION: http://" + String (s) + " :80/description.xml\r\n "
293
+ " LOCATION: http://%s :80/description.xml\r\n "
298
294
" SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n " // _modelName, _modelNumber
299
- " hue-bridgeid: " + escapedMac + " \r\n "
295
+ " hue-bridgeid: %s \r\n "
300
296
" ST: urn:schemas-upnp-org:device:basic:1\r\n " // _deviceType
301
- " USN: uuid:2f402f80-da50-11e1-9b23-" + escapedMac + " ::ssdp:all\r\n " // _uuid::_deviceType
302
- " \r\n " ;
297
+ " USN: uuid:2f402f80-da50-11e1-9b23-%s ::ssdp:all\r\n " // _uuid::_deviceType
298
+ " \r\n " ),s,escapedMac. c_str (),escapedMac. c_str ()) ;
303
299
304
300
espalexaUdp.beginPacket (espalexaUdp.remoteIP (), espalexaUdp.remotePort ());
305
301
#ifdef ARDUINO_ARCH_ESP32
306
- espalexaUdp.write ((uint8_t *)response. c_str () , response.length ());
302
+ espalexaUdp.write ((uint8_t *)buf , response.length ());
307
303
#else
308
- espalexaUdp.write (response. c_str () );
304
+ espalexaUdp.write (buf );
309
305
#endif
310
306
espalexaUdp.endPacket ();
311
307
}
@@ -362,7 +358,8 @@ class Espalexa {
362
358
if (!packetSize) return ; // no new udp packet
363
359
364
360
EA_DEBUGLN (" Got UDP!" );
365
- int len = espalexaUdp.read (packetBuffer, 254 );
361
+ char packetBuffer[255 ]; // buffer to hold incoming udp packet
362
+ uint16_t len = espalexaUdp.read (packetBuffer, 254 );
366
363
if (len > 0 ) {
367
364
packetBuffer[len] = 0 ;
368
365
}
@@ -447,13 +444,13 @@ class Espalexa {
447
444
{
448
445
EA_DEBUGLN (" devType" );
449
446
body = " " ;
450
- server->send (200 , " application/json" , " [{\" success\" :{\" username\" :\" 2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\" }}]" );
447
+ server->send (200 , " application/json" , F ( " [{\" success\" :{\" username\" :\" 2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\" }}]" ) );
451
448
return true ;
452
449
}
453
450
454
451
if (req.indexOf (" state" ) > 0 ) // client wants to control light
455
452
{
456
- server->send (200 , " application/json" , " [{\" success\" :{\" /lights/1/state/\" : true}}]" );
453
+ server->send (200 , " application/json" , F ( " [{\" success\" :{\" /lights/1/state/\" : true}}]" ) );
457
454
458
455
uint32_t devId = req.substring (req.indexOf (" lights" )+7 ).toInt ();
459
456
EA_DEBUG (" ls" ); EA_DEBUGLN (devId);
@@ -530,7 +527,9 @@ class Espalexa {
530
527
for (int i = 0 ; i<currentDeviceCount; i++)
531
528
{
532
529
jsonTemp += " \" " + String (encodeLightId (i+1 )) + " \" :" ;
533
- jsonTemp += deviceJsonString (i+1 );
530
+ char buf[512 ];
531
+ deviceJsonString (i+1 , buf);
532
+ jsonTemp += buf;
534
533
if (i < currentDeviceCount-1 ) jsonTemp += " ," ;
535
534
}
536
535
jsonTemp += " }" ;
@@ -543,7 +542,9 @@ class Espalexa {
543
542
{
544
543
server->send (200 , " application/json" , " {}" );
545
544
} else {
546
- server->send (200 , " application/json" , deviceJsonString (devId));
545
+ char buf[512 ];
546
+ deviceJsonString (devId, buf);
547
+ server->send (200 , " application/json" , buf);
547
548
}
548
549
}
549
550
0 commit comments