From bbac070c091bb3d2562fe3b1c505e4ca340c1cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Fri, 20 Jan 2017 13:30:52 +0100 Subject: [PATCH] Pass safe buffer to api callbacks --- code/espurna/config/general.h | 2 +- code/espurna/config/prototypes.h | 2 +- code/espurna/dht.ino | 43 +++++++++++++++++------------ code/espurna/ds18b20.ino | 22 +++++++++------ code/espurna/emon.ino | 47 ++++++++++++++++++-------------- code/espurna/pow.ino | 15 ++++------ code/espurna/relay.ino | 4 +-- code/espurna/web.ino | 11 ++++++-- 8 files changed, 84 insertions(+), 62 deletions(-) diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 3032f5d8..c00fad50 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -81,7 +81,7 @@ #define MQTT_MESSAGE_EVENT 2 // Custom get and set postfixes -// Use something like "/status" or "/set", with trailing slash +// Use something like "/status" or "/set", with leading slash #define MQTT_USE_GETTER "" #define MQTT_USE_SETTER "" diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index 6311efb3..2c4fe604 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -5,7 +5,7 @@ #include #include -typedef std::function apiGetCallbackFunction; +typedef std::function apiGetCallbackFunction; typedef std::function apiPutCallbackFunction; void apiRegister(const char * url, const char * key, apiGetCallbackFunction getFn, apiPutCallbackFunction putFn = NULL); void mqttRegister(void (*callback)(unsigned int, const char *, const char *)); diff --git a/code/espurna/dht.ino b/code/espurna/dht.ino index 502bcbdb..61ba98f5 100644 --- a/code/espurna/dht.ino +++ b/code/espurna/dht.ino @@ -13,25 +13,29 @@ Copyright (C) 2016-2017 by Xose Pérez DHT dht(DHT_PIN, DHT_TYPE, DHT_TIMING); -char dhtTemperature[6]; -char dhtHumidity[6]; +double _dhtTemperature = 0; +unsigned int _dhtHumidity = 0; // ----------------------------------------------------------------------------- // Values // ----------------------------------------------------------------------------- -char * getDHTTemperature() { - return dhtTemperature; +double getDHTTemperature() { + return _dhtTemperature; } -char * getDHTHumidity() { - return dhtHumidity; +unsigned int getDHTHumidity() { + return _dhtHumidity; } void dhtSetup() { dht.begin(); - apiRegister("/api/temperature", "temperature", getDHTTemperature); - apiRegister("/api/humidity", "humidity", getDHTHumidity); + apiRegister("/api/temperature", "temperature", [](char * buffer, size_t len) { + dtostrf(_dhtTemperature, len-1, 1, buffer); + }); + apiRegister("/api/humidity", "humidity", [](char * buffer, size_t len) { + snprintf(buffer, len, "%d", _dhtHumidity); + }); } void dhtLoop() { @@ -52,25 +56,30 @@ void dhtLoop() { } else { - dtostrf(t, 4, 1, dhtTemperature); - itoa((int) h, dhtHumidity, 10); + _dhtTemperature = t; + _dhtHumidity = h; - DEBUG_MSG("[DHT] Temperature: %s\n", dhtTemperature); - DEBUG_MSG("[DHT] Humidity: %s\n", dhtHumidity); + char temperature[6]; + char humidity[6]; + dtostrf(t, 4, 1, temperature); + itoa((unsigned int) h, humidity, 10); + + DEBUG_MSG("[DHT] Temperature: %s\n", temperature); + DEBUG_MSG("[DHT] Humidity: %s\n", humidity); // Send MQTT messages - mqttSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), dhtTemperature); - mqttSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), dhtHumidity); + mqttSend(getSetting("dhtTmpTopic", DHT_TEMPERATURE_TOPIC).c_str(), temperature); + mqttSend(getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity); // Send to Domoticz #if ENABLE_DOMOTICZ - domoticzSend("dczTmpIdx", dhtTemperature); - domoticzSend("dczHumIdx", dhtHumidity); + domoticzSend("dczTmpIdx", temperature); + domoticzSend("dczHumIdx", humidity); #endif // Update websocket clients char buffer[100]; - sprintf_P(buffer, PSTR("{\"dhtVisible\": 1, \"dhtTmp\": %s, \"dhtHum\": %s}"), dhtTemperature, dhtHumidity); + sprintf_P(buffer, PSTR("{\"dhtVisible\": 1, \"dhtTmp\": %s, \"dhtHum\": %s}"), temperature, humidity); wsSend(buffer); } diff --git a/code/espurna/ds18b20.ino b/code/espurna/ds18b20.ino index b4fc6795..2011530f 100644 --- a/code/espurna/ds18b20.ino +++ b/code/espurna/ds18b20.ino @@ -14,19 +14,21 @@ Copyright (C) 2016-2017 by Xose Pérez OneWire oneWire(DS_PIN); DallasTemperature ds18b20(&oneWire); -char dsTemperature[6]; +double _dsTemperature = 0; // ----------------------------------------------------------------------------- // DS18B20 // ----------------------------------------------------------------------------- -char * getDSTemperature() { - return dsTemperature; +double getDSTemperature() { + return _dsTemperature; } void dsSetup() { ds18b20.begin(); - apiRegister("/api/temperature", "temperature", getDSTemperature); + apiRegister("/api/temperature", "temperature", [](char * buffer, size_t len) { + dtostrf(_dsTemperature, len-1, 1, buffer); + }); } void dsLoop() { @@ -49,21 +51,23 @@ void dsLoop() { } else { - dtostrf(t, 4, 1, dsTemperature); + _dsTemperature = t; - DEBUG_MSG("[DS18B20] Temperature: %s\n", dsTemperature); + char temperature[6]; + dtostrf(t, 5, 1, temperature); + DEBUG_MSG("[DS18B20] Temperature: %s\n", temperature); // Send MQTT messages - mqttSend(getSetting("dsTmpTopic", DS_TEMPERATURE_TOPIC).c_str(), dsTemperature); + mqttSend(getSetting("dsTmpTopic", DS_TEMPERATURE_TOPIC).c_str(), temperature); // Send to Domoticz #if ENABLE_DOMOTICZ - domoticzSend("dczTmpIdx", dsTemperature); + domoticzSend("dczTmpIdx", temperature); #endif // Update websocket clients char buffer[100]; - sprintf_P(buffer, PSTR("{\"dsVisible\": 1, \"dsTmp\": %s}"), dsTemperature); + sprintf_P(buffer, PSTR("{\"dsVisible\": 1, \"dsTmp\": %s}"), temperature); wsSend(buffer); } diff --git a/code/espurna/emon.ino b/code/espurna/emon.ino index b41c0345..c9abb550 100644 --- a/code/espurna/emon.ino +++ b/code/espurna/emon.ino @@ -11,8 +11,8 @@ Copyright (C) 2016-2017 by Xose Pérez #include EmonLiteESP emon; -double current; -char power[8]; +double _current = 0; +unsigned int _power = 0; // ----------------------------------------------------------------------------- // EMON @@ -22,12 +22,12 @@ void setCurrentRatio(float value) { emon.setCurrentRatio(value); } -char * getPower() { - return power; +unsigned int getPower() { + return _power; } double getCurrent() { - return current; + return _current; } unsigned int currentCallback() { @@ -53,7 +53,9 @@ void powerMonitorSetup() { ); emon.setPrecision(EMON_CURRENT_PRECISION); - apiRegister("/api/power", "power", getPower); + apiRegister("/api/power", "power", [](char * buffer, size_t len) { + snprintf(buffer, len, "%d", _power); + }); } @@ -77,41 +79,46 @@ void powerMonitorLoop() { // Safety check: do not read current if relay is OFF if (!relayStatus(0)) { - current = 0; + _current = 0; } else { - current = emon.getCurrent(EMON_SAMPLES); - current -= EMON_CURRENT_OFFSET; - if (current < 0) current = 0; + _current = emon.getCurrent(EMON_SAMPLES); + _current -= EMON_CURRENT_OFFSET; + if (_current < 0) _current = 0; } if (measurements == 0) { - max = min = current; + max = min = _current; } else { - if (current > max) max = current; - if (current < min) min = current; + if (_current > max) max = _current; + if (_current < min) min = _current; } - sum += current; + sum += _current; ++measurements; float mainsVoltage = getSetting("emonMains", EMON_MAINS_VOLTAGE).toFloat(); - //DEBUG_MSG("[ENERGY] Power now: %dW\n", int(current * mainsVoltage)); + //DEBUG_MSG("[ENERGY] Power now: %dW\n", int(_current * mainsVoltage)); // Update websocket clients char text[20]; - sprintf_P(text, PSTR("{\"emonPower\": %d}"), int(current * mainsVoltage)); + sprintf_P(text, PSTR("{\"emonPower\": %d}"), int(_current * mainsVoltage)); wsSend(text); // Send MQTT messages averaged every EMON_MEASUREMENTS if (measurements == EMON_MEASUREMENTS) { - double p = (sum - max - min) * mainsVoltage / (measurements - 2); - sprintf(power, "%d", int(p)); + + _power = (int) ((sum - max - min) * mainsVoltage / (measurements - 2)); + sum = 0; + measurements = 0; + + char power[6]; + snprintf(power, "%d", 6, _power); mqttSend(getSetting("emonPowerTopic", EMON_POWER_TOPIC).c_str(), power); #if ENABLE_DOMOTICZ domoticzSend("dczPowIdx", power); #endif - sum = 0; - measurements = 0; + + } next_measurement += EMON_INTERVAL; diff --git a/code/espurna/pow.ino b/code/espurna/pow.ino index 5196ee35..606adb2b 100644 --- a/code/espurna/pow.ino +++ b/code/espurna/pow.ino @@ -144,17 +144,14 @@ void powSetup() { powAttachInterrupts(); #endif - apiRegister("/api/power", "power", []() { - sprintf(apibuffer, "%d", getActivePower()); - return apibuffer; + apiRegister("/api/power", "power", [](char * buffer, size_t len) { + snprintf(buffer, len, "%d", getActivePower()); }); - apiRegister("/api/current", "current", []() { - dtostrf(getCurrent(), 5, 2, apibuffer); - return apibuffer; + apiRegister("/api/current", "current", [](char * buffer, size_t len) { + dtostrf(getCurrent(), len-1, 2, buffer); }); - apiRegister("/api/voltage", "voltage", []() { - sprintf(apibuffer, "%d", getVoltage()); - return apibuffer; + apiRegister("/api/voltage", "voltage", [](char * buffer, size_t len) { + snprintf(buffer, len, "%d", getVoltage()); }); } diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino index d99c2b6b..a5c0e892 100644 --- a/code/espurna/relay.ino +++ b/code/espurna/relay.ino @@ -181,8 +181,8 @@ void relaySetupAPI() { sprintf(key, "relay%d", relayID); apiRegister(url, key, - [relayID]() { - return (char *) (relayStatus(relayID) ? "1" : "0"); + [relayID](char * buffer, size_t len) { + snprintf(buffer, "%d", len, relayStatus(relayID) ? 1 : 0); }, [relayID](const char * payload) { unsigned int value = payload[0] - '0'; diff --git a/code/espurna/web.ino b/code/espurna/web.ino index 5396275e..0c00e78f 100644 --- a/code/espurna/web.ino +++ b/code/espurna/web.ino @@ -535,14 +535,19 @@ ArRequestHandlerFunction _bindAPI(unsigned int apiID) { } } - char * value = strdup((api.getFn)()); + char value[10]; + (api.getFn)(value, 10); + + // jump over leading spaces + char *p = value; + while ((unsigned char) *p == ' ') ++p; if (asJson) { char buffer[64]; - sprintf_P(buffer, PSTR("{ \"%s\": %s }"), api.key, value); + sprintf_P(buffer, PSTR("{ \"%s\": %s }"), api.key, p); request->send(200, "application/json", buffer); } else { - request->send(200, "text/plain", value); + request->send(200, "text/plain", p); } };