@@ -276,7 +276,7 @@
@@ -287,20 +287,9 @@
-
AC RMS Voltage
-
This is your house nominal voltage, you probably know this or you wont be playing with this device...
-
- 125
- 220
- 230
- 240
-
-
-
-
-
Current Ratio
-
This is the value in amps for a 1V output for your sensor. Some current sensors like the YHDC SCT-013-030 have it written in the enclosure: 30A 1V. If you are using a current sensor that outputs a current (no built in burden resistor) it will depend on the turns ratio between the primary and secondary coils in the sensor and the burden resistor you use. Check about this constant in the
post about calibration in the Open Energy Monitor site.
-
+
AC RMS Active Power
+
If you are using a pure resistive load like a bulb this will be writen on it, otherwise use a socket multimeter to get this value.
+
diff --git a/code/lib/HLW8012 b/code/lib/HLW8012
new file mode 160000
index 00000000..1dfa68b9
--- /dev/null
+++ b/code/lib/HLW8012
@@ -0,0 +1 @@
+Subproject commit 1dfa68b9e79a4a8ea96df4ed20f64e0c12ee9d26
diff --git a/code/platformio.custom.ini b/code/platformio.custom.ini
index f5e66534..f57c87a9 100644
--- a/code/platformio.custom.ini
+++ b/code/platformio.custom.ini
@@ -12,7 +12,7 @@ env_default = node-debug
[common]
platform = espressif8266
framework = arduino
-lib_install = 19,44,64,89,549,727
+lib_install = 19,31,44,64,89,549,727
extra_script = pio_hooks.py
[ota]
@@ -28,6 +28,14 @@ build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
[env:sonoff-debug-ota]
include = env:sonoff-debug,ota
+[env:sonoff-pow-debug]
+include = common
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF_POW
+
+[env:sonoff-pow-debug-ota]
+include = env:sonoff-pow-debug,ota
+
[env:slampher-debug]
include = common
board = esp01_1m
@@ -71,4 +79,4 @@ include = env:sonoff-debug-ota
[env:living-lamp-device]
topic = /home/living/lamp/ip
-include = env:sonoff-debug-ota
+include = env:s20-debug-ota
diff --git a/code/platformio.ini b/code/platformio.ini
index fa07d532..8400b7c6 100644
--- a/code/platformio.ini
+++ b/code/platformio.ini
@@ -1,5 +1,5 @@
[platformio]
-env_default = node-debug
+env_default = sonoff-pow-debug
[env:sonoff-debug]
platform = espressif8266
@@ -20,6 +20,14 @@ upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
+[env:sonoff-pow-debug]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF_POW
+
[env:slampher-debug]
platform = espressif8266
framework = arduino
diff --git a/code/platformio.official.ini b/code/platformio.official.ini
new file mode 100644
index 00000000..8400b7c6
--- /dev/null
+++ b/code/platformio.official.ini
@@ -0,0 +1,136 @@
+[platformio]
+env_default = sonoff-pow-debug
+
+[env:sonoff-debug]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
+
+[env:sonoff-debug-ota]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
+
+[env:sonoff-pow-debug]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF_POW
+
+[env:slampher-debug]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSLAMPHER
+
+[env:slampher-debug-ota]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSLAMPHER
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
+
+[env:s20-debug]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20
+
+[env:s20-debug-ota]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
+
+[env:node-debug]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = nodemcuv2
+build_flags = -DNODEMCUV2 -DDEBUG_PORT=Serial
+
+[env:node-debug-ota]
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = nodemcuv2
+build_flags = -DNODEMCUV2 -DDEBUG_PORT=Serial
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
+
+
+
+[env:ac-device]
+topic = /home/cellar/airconditioner/ip
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DS20
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
+
+[env:washer-device]
+topic = /home/cellar/washer/ip
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF -DENABLE_EMON=1 -DENABLE_DHT=1
+
+[env:studio-lamp-device]
+topic = /home/studio/lamp/ip
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
+
+[env:living-lamp-device]
+topic = /home/living/lamp/ip
+platform = espressif8266
+framework = arduino
+lib_install = 19,31,44,64,89,549,727
+extra_script = pio_hooks.py
+board = esp01_1m
+build_flags = -Wl,-Tesp8266.flash.1m256.ld -DDEBUG_PORT=Serial -DSONOFF
+upload_speed = 115200
+upload_port = "192.168.4.1"
+upload_flags = --auth=fibonacci --port 8266
diff --git a/code/src/defaults.h b/code/src/defaults.h
index bf18832e..996c05f3 100644
--- a/code/src/defaults.h
+++ b/code/src/defaults.h
@@ -14,6 +14,7 @@
//#define ENABLE_EMON 1
//#define ENABLE_DHT 1
//#define ENABLE_RF 1
+//#define ENABLE_POW 1
// -----------------------------------------------------------------------------
// HARDWARE
@@ -35,6 +36,13 @@
#define LED_PIN 13
#endif
+#ifdef SONOFF_POW
+ #define ENABLE_POW 1
+ #define MANUFACTURER "ITEAD"
+ #define DEVICE "SONOFF_POW"
+ #define LED_PIN 13
+#endif
+
#ifdef SLAMPHER
#define MANUFACTURER "ITEAD"
#define DEVICE "SLAMPHER"
@@ -124,3 +132,14 @@
#define EMON_MAINS_VOLTAGE 230
#define EMON_CURRENT_RATIO 180
#define EMON_POWER_TOPIC "/power"
+
+#define POW_SEL_PIN 5
+#define POW_CF1_PIN 13
+#define POW_CF_PIN 14
+#define POW_SEL_CURRENT HIGH
+#define POW_CURRENT_R 0.001
+#define POW_VOLTAGE_R_UP ( 5 * 470000 ) // Real: 2280k
+#define POW_VOLTAGE_R_DOWN ( 1000 ) // Real 1.009k
+#define POW_POWER_TOPIC "/power"
+#define POW_UPDATE_INTERVAL 10000
+#define POW_REPORT_EVERY 6
diff --git a/code/src/dht.ino b/code/src/dht.ino
index a1af8d2a..fe412fc2 100644
--- a/code/src/dht.ino
+++ b/code/src/dht.ino
@@ -64,8 +64,8 @@ void dhtLoop() {
mqttSend((char *) getSetting("dhtHumTopic", DHT_HUMIDITY_TOPIC).c_str(), humidity);
// Update websocket clients
- char buffer[20];
- sprintf_P(buffer, PSTR("{\"dhtTmp\": %s, \"dhtHum\": %s}"), temperature, humidity);
+ char buffer[100];
+ sprintf_P(buffer, PSTR("{\"dhtVisible\": 1, \"dhtTmp\": %s, \"dhtHum\": %s}"), temperature, humidity);
webSocketSend(buffer);
}
diff --git a/code/src/main.ino b/code/src/main.ino
index 6d6e81e0..26b91b36 100644
--- a/code/src/main.ino
+++ b/code/src/main.ino
@@ -151,6 +151,9 @@ void setup() {
#if ENABLE_NOFUSS
nofussSetup();
#endif
+ #if ENABLE_POW
+ powSetup();
+ #endif
#if ENABLE_DHT
dhtSetup();
#endif
@@ -178,6 +181,9 @@ void loop() {
#if ENABLE_NOFUSS
nofussLoop();
#endif
+ #if ENABLE_POW
+ powLoop();
+ #endif
#if ENABLE_DHT
dhtLoop();
#endif
diff --git a/code/src/pow.ino b/code/src/pow.ino
new file mode 100644
index 00000000..93260332
--- /dev/null
+++ b/code/src/pow.ino
@@ -0,0 +1,160 @@
+/*
+
+ESPurna
+POW MODULE
+Support for Sonoff POW HLW8012-based power monitor
+
+Copyright (C) 2016 by Xose Pérez
+
+*/
+
+#if ENABLE_POW
+
+#include
+
+HLW8012 hlw8012;
+
+// -----------------------------------------------------------------------------
+// POW
+// -----------------------------------------------------------------------------
+
+// When using interrupts we have to call the library entry point
+// whenever an interrupt is triggered
+void hlw8012_cf1_interrupt() {
+ hlw8012.cf1_interrupt();
+}
+
+void hlw8012_cf_interrupt() {
+ hlw8012.cf_interrupt();
+}
+
+void powAttachInterrupts() {
+ //attachInterrupt(POW_CF1_PIN, hlw8012_cf1_interrupt, CHANGE);
+ attachInterrupt(POW_CF_PIN, hlw8012_cf_interrupt, CHANGE);
+ DEBUG_MSG("[POW] Enabled\n");
+}
+
+void powDettachInterrupts() {
+ //detachInterrupt(POW_CF1_PIN);
+ detachInterrupt(POW_CF_PIN);
+ DEBUG_MSG("[POW] Disabled\n");
+}
+
+void powSaveCalibration() {
+ setSetting("powPowerMult", String() + hlw8012.getPowerMultiplier());
+ setSetting("powCurrentMult", String() + hlw8012.getCurrentMultiplier());
+ setSetting("powVoltageMult", String() + hlw8012.getVoltageMultiplier());
+}
+
+void powRetrieveCalibration() {
+ double value;
+ value = getSetting("powPowerMult", "0").toFloat();
+ if (value > 0) hlw8012.setPowerMultiplier((int) value);
+ value = getSetting("powCurrentMult", "0").toFloat();
+ if (value > 0) hlw8012.setCurrentMultiplier((int) value);
+ value = getSetting("powVoltageMult", "0").toFloat();
+ if (value > 0) hlw8012.setVoltageMultiplier((int) value);
+}
+
+void powSetExpectedActivePower(unsigned int power) {
+ if (power > 0) {
+ hlw8012.expectedActivePower(power);
+ powSaveCalibration();
+ }
+}
+
+void powSetExpectedCurrent(double current) {
+ if (current > 0) {
+ hlw8012.expectedCurrent(current);
+ powSaveCalibration();
+ }
+}
+
+void powSetExpectedVoltage(unsigned int voltage) {
+ if (voltage > 0) {
+ hlw8012.expectedVoltage(voltage);
+ powSaveCalibration();
+ }
+}
+
+unsigned int getActivePower() {
+ return hlw8012.getActivePower();
+}
+
+unsigned int getApparentPower() {
+ return hlw8012.getApparentPower();
+}
+
+double getCurrent() {
+ return hlw8012.getCurrent();
+}
+
+unsigned int getVoltage() {
+ return hlw8012.getVoltage();
+}
+
+unsigned int getPowerFactor() {
+ return (int) (100 * hlw8012.getPowerFactor());
+}
+
+void powSetup() {
+
+ // Initialize HLW8012
+ // void begin(unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = false, unsigned long pulse_timeout = PULSE_TIMEOUT);
+ // * cf_pin, cf1_pin and sel_pin are GPIOs to the HLW8012 IC
+ // * currentWhen is the value in sel_pin to select current sampling
+ // * set use_interrupts to true to use interrupts to monitor pulse widths
+ // * leave pulse_timeout to the default value, recommended when using interrupts
+ hlw8012.begin(POW_CF_PIN, POW_CF1_PIN, POW_SEL_PIN, POW_SEL_CURRENT, true);
+
+ // These values are used to calculate current, voltage and power factors as per datasheet formula
+ // These are the nominal values for the Sonoff POW resistors:
+ // * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
+ // * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
+ // * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
+ hlw8012.setResistors(POW_CURRENT_R, POW_VOLTAGE_R_UP, POW_VOLTAGE_R_DOWN);
+
+ powRetrieveCalibration();
+
+ static WiFiEventHandler e1 = WiFi.onStationModeDisconnected([](const WiFiEventStationModeDisconnected& event) {
+ powDettachInterrupts();
+ });
+
+ static WiFiEventHandler e2 = WiFi.onSoftAPModeStationDisconnected([](const WiFiEventSoftAPModeStationDisconnected& event) {
+ powDettachInterrupts();
+ });
+
+ static WiFiEventHandler e3 = WiFi.onStationModeConnected([](const WiFiEventStationModeConnected& event) {
+ powAttachInterrupts();
+ });
+
+ static WiFiEventHandler e4 = WiFi.onSoftAPModeStationConnected([](const WiFiEventSoftAPModeStationConnected& event) {
+ powAttachInterrupts();
+ });
+
+}
+
+void powLoop() {
+
+ static unsigned long last_update = 0;
+ static unsigned char report_count = POW_REPORT_EVERY;
+
+ if ((millis() - last_update > POW_UPDATE_INTERVAL) || (last_update == 0 )){
+ last_update = millis();
+
+ unsigned int power = getActivePower();
+
+ char buffer[100];
+ sprintf_P(buffer, PSTR("{\"powVisible\": 1, \"powActivePower\": %d}"), power);
+ webSocketSend(buffer);
+
+ if (--report_count == 0) {
+ mqttSend((char *) getSetting("powPowerTopic", POW_POWER_TOPIC).c_str(), (char *) String(power).c_str());
+ report_count = POW_REPORT_EVERY;
+ }
+
+ }
+
+}
+
+#endif
diff --git a/code/src/version.h b/code/src/version.h
index 63d924f3..624ada9e 100644
--- a/code/src/version.h
+++ b/code/src/version.h
@@ -1,4 +1,4 @@
#define APP_NAME "Espurna"
-#define APP_VERSION "0.9.8"
+#define APP_VERSION "0.9.9"
#define APP_AUTHOR "xose.perez@gmail.com"
#define APP_WEBSITE "http://tinkerman.cat"
diff --git a/code/src/websockets.ino b/code/src/websockets.ino
index f2bfa48b..8bab19be 100644
--- a/code/src/websockets.ino
+++ b/code/src/websockets.ino
@@ -67,6 +67,15 @@ void webSocketParse(uint8_t num, uint8_t * payload, size_t length) {
String key = config[i]["name"];
String value = config[i]["value"];
+ #if ENABLE_POW
+
+ if (key == "powExpectedPower") {
+ powSetExpectedActivePower(value.toInt());
+ continue;
+ }
+
+ #endif
+
if (key == "ssid") {
key = key + String(network);
}
@@ -137,21 +146,29 @@ void webSocketStart(uint8_t num) {
root["relayMode"] = getSetting("relayMode", String(RELAY_MODE));
#if ENABLE_DHT
+ root["dhtVisible"] = 1;
root["dhtTmp"] = getTemperature();
root["dhtHum"] = getHumidity();
#endif
#if ENABLE_RF
+ root["rfVisible"] = 1;
root["rfChannel"] = getSetting("rfChannel", String(RF_CHANNEL));
root["rfDevice"] = getSetting("rfDevice", String(RF_DEVICE));
#endif
#if ENABLE_EMON
+ root["emonVisible"] = 1;
root["emonPower"] = getPower();
root["emonMains"] = getSetting("emonMains", String(EMON_MAINS_VOLTAGE));
root["emonRatio"] = getSetting("emonRatio", String(EMON_CURRENT_RATIO));
#endif
+ #if ENABLE_POW
+ root["powVisible"] = 1;
+ root["powActivePower"] = getActivePower();
+ #endif
+
JsonArray& wifi = root.createNestedArray("wifi");
for (byte i=0; i<3; i++) {
JsonObject& network = wifi.createNestedObject();