diff --git a/.travis.yml b/.travis.yml
index bb8628ff..7b1b8c3f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,7 +11,7 @@ cache:
install:
- pip install -U platformio
- npm install -g npm@latest
-- cd code ; npm ci ; cd ..
+- cd code && npm ci && cd ..
env:
global:
- BUILDER_TOTAL_THREADS=4
diff --git a/README.md b/README.md
index 5cdbd3ef..ea71bce3 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,11 @@ ESPurna ("spark" in Catalan) is a custom firmware for ESP8285/ESP8266 based smar
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
[![version](https://img.shields.io/badge/version-1.13.3-brightgreen.svg)](CHANGELOG.md)
-[![branch](https://img.shields.io/badge/branch-master-orange.svg)](https://github.com/xoseperez/espurna/tree/master/)
-[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=master)](https://travis-ci.org/xoseperez/espurna)
-[![codacy](https://api.codacy.com/project/badge/Grade/c9496e25cf07434cba786b462cb15f49)](https://www.codacy.com/app/xoseperez/espurna/dashboard)
+[![branch](https://img.shields.io/badge/branch-dev-orange.svg)](https://github.com/xoseperez/espurna/tree/dev/)
[![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE)
+[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=dev)](https://travis-ci.org/xoseperez/espurna)
+[![codacy](https://api.codacy.com/project/badge/Grade/c9496e25cf07434cba786b462cb15f49)](https://www.codacy.com/app/xoseperez/espurna/dashboard)
+[![downloads](https://img.shields.io/github/downloads/xoseperez/espurna/total.svg)](https://github.com/xoseperez/espurna/releases)
[![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=xose%2eperez%40gmail%2ecom&lc=US&no_note=0¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest)
[![gitter](https://img.shields.io/gitter/room/tinkermant-cat/espurna.svg)](https://gitter.im/tinkerman-cat/espurna)
@@ -239,8 +240,8 @@ Here is the list of supported hardware. For more information please refer to the
|**Maxcio W-US002S**|**HEYGO HY02**|**YiDian XS-SSA05**|
|![WiOn 50055](images/devices/wion-50055.jpg)|![LINGAN SWA1](images/devices/lingan-swa1.jpg)|![HomeCube 16A](images/devices/homecube-16a.jpg)|
|**WiOn 50055**|**LINGAN SWA1**|**HomeCube 16A**|
-|![WorkChoice EcoPlug](images/devices/workchoice-ecoplug.jpg)|![Bestek MRJ1011](images/devices/bestek-mrj1011.jpg)||
-|**WorkChoice EcoPlug**|**Bestek MRJ1011**||
+|![WorkChoice EcoPlug](images/devices/workchoice-ecoplug.jpg)|![Bestek MRJ1011](images/devices/bestek-mrj1011.jpg)|![Tonbux XS-SSA01](images/devices/tonbux-xs-ssa01.jpg)|
+|**WorkChoice EcoPlug**|**Bestek MRJ1011**|**Tonbux XS-SSA01**|
|![Tonbux PowerStrip02](images/devices/tonbux-powerstrip02.jpg)|![ForNorm Power Strip](images/devices/fornorm-power-strip.jpg)|![Zhilde ZLD-EU55-W](images/devices/zhilde-zld-eu55-w.jpg)|
|**Tonbux PowerStrip02**|**Fornorm Power Strip**|**Zhilde ZLD-EU55-W**|
|![Itead Sonoff Touch](images/devices/itead-sonoff-touch.jpg)|![Itead Sonoff T1](images/devices/itead-sonoff-t1.jpg)|![YJZK switch](images/devices/yjzk-2gang-switch.jpg)|
diff --git a/code/espurna/api.ino b/code/espurna/api.ino
index 705fee17..f65f03f9 100644
--- a/code/espurna/api.ino
+++ b/code/espurna/api.ino
@@ -221,6 +221,7 @@ void apiRegister(const char * key, api_get_callback_f getFn, api_put_callback_f
}
void apiSetup() {
+ _apiConfigure();
wsOnSendRegister(_apiWebSocketOnSend);
wsOnReceiveRegister(_apiWebSocketOnReceive);
webRequestRegister(_apiRequestCallback);
diff --git a/code/espurna/config/arduino.h b/code/espurna/config/arduino.h
index fe4b081a..5625972a 100644
--- a/code/espurna/config/arduino.h
+++ b/code/espurna/config/arduino.h
@@ -72,6 +72,7 @@
//#define MAXCIO_WUS002S
//#define YIDIAN_XSSSA05
//#define TONBUX_XSSSA06
+//#define TONBUX_XSSSA01
//#define GREEN_ESP8266RELAY
//#define IKE_ESPIKE
//#define ARNIEX_SWIFITCH
@@ -172,3 +173,4 @@
//#define SONAR_SUPPORT 1
//#define TMP3X_SUPPORT 1
//#define V9261F_SUPPORT 1
+//#define VL53L1X_SUPPORT 1
diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h
index 04850ea1..307c6eb7 100644
--- a/code/espurna/config/general.h
+++ b/code/espurna/config/general.h
@@ -187,6 +187,7 @@
// Topics that will be reported in heartbeat
#define HEARTBEAT_REPORT_STATUS 1
+#define HEARTBEAT_REPORT_SSID 1
#define HEARTBEAT_REPORT_IP 1
#define HEARTBEAT_REPORT_MAC 1
#define HEARTBEAT_REPORT_RSSI 1
@@ -236,6 +237,9 @@
#ifndef BUTTON_LNGLNGCLICK_DELAY
#define BUTTON_LNGLNGCLICK_DELAY 10000 // Time in ms holding the button down to get a long-long click
+#endif
+
+#ifndef BUTTON_MQTT_SEND_ALL_EVENTS
#define BUTTON_MQTT_SEND_ALL_EVENTS 0 // 0 - to send only events the are bound to actions
// 1 - to send all button events to MQTT
#endif
@@ -434,7 +438,9 @@
// or in the Internet. Since the WebUI is just one compressed file with HTML, CSS and JS
// there are no special requirements. Any static web server will do (NGinx, Apache, Lighttpd,...).
// The only requirement is that the resource must be available under this domain.
+#ifndef WEB_REMOTE_DOMAIN
#define WEB_REMOTE_DOMAIN "http://tinkerman.cat"
+#endif
// -----------------------------------------------------------------------------
// WEBSOCKETS
@@ -731,6 +737,7 @@
#define MQTT_TOPIC_LED "led"
#define MQTT_TOPIC_BUTTON "button"
#define MQTT_TOPIC_IP "ip"
+#define MQTT_TOPIC_SSID "ssid"
#define MQTT_TOPIC_VERSION "version"
#define MQTT_TOPIC_UPTIME "uptime"
#define MQTT_TOPIC_DATETIME "datetime"
@@ -925,8 +932,13 @@
#define HOMEASSISTANT_SUPPORT MQTT_SUPPORT // Build with home assistant support (if MQTT, 1.64Kb)
#endif
+#ifndef HOMEASSISTANT_ENABLED
#define HOMEASSISTANT_ENABLED 0 // Integration not enabled by default
+#endif
+
+#ifndef HOMEASSISTANT_PREFIX
#define HOMEASSISTANT_PREFIX "homeassistant" // Default MQTT prefix
+#endif
#ifndef HOMEASSISTANT_PAYLOAD_ON
#define HOMEASSISTANT_PAYLOAD_ON "1" // Payload for ON and available messages
diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h
index 6068a274..9d40c0ef 100644
--- a/code/espurna/config/hardware.h
+++ b/code/espurna/config/hardware.h
@@ -1920,6 +1920,29 @@
#define HLW8012_CURRENT_R 0.002 // Current resistor
#define HLW8012_VOLTAGE_R_UP ( 2 * 1000000 ) // Upstream voltage resistor
+// -----------------------------------------------------------------------------
+// Maxcio W-DE004
+// -----------------------------------------------------------------------------
+
+#elif defined(MAXCIO_WDE004)
+
+ // Info
+ #define MANUFACTURER "MAXCIO"
+ #define DEVICE "WDE004"
+
+ // Buttons
+ #define BUTTON1_PIN 1
+ #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
+ #define BUTTON1_RELAY 1
+
+ // Relays
+ #define RELAY1_PIN 14
+ #define RELAY1_TYPE RELAY_TYPE_NORMAL
+
+ // LEDs
+ #define LED1_PIN 13
+ #define LED1_PIN_INVERSE 1
+
// -----------------------------------------------------------------------------
// YiDian XS-SSA05
// -----------------------------------------------------------------------------
@@ -1962,6 +1985,29 @@
#define HLW8012_POWER_RATIO 3414290
#define HLW8012_INTERRUPT_ON FALLING
+// -----------------------------------------------------------------------------
+// TONBUX XS-SSA01
+// -----------------------------------------------------------------------------
+
+#elif defined(TONBUX_XSSSA01)
+
+ // Info
+ #define MANUFACTURER "TONBUX"
+ #define DEVICE "XSSSA01"
+
+ // Buttons
+ #define BUTTON1_PIN 4
+ #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
+ #define BUTTON1_RELAY 1
+
+ // Relays
+ #define RELAY1_PIN 14
+ #define RELAY1_TYPE RELAY_TYPE_NORMAL
+
+ // LEDs
+ #define LED1_PIN 13
+ #define LED1_PIN_INVERSE 0
+
// -----------------------------------------------------------------------------
// TONBUX XS-SSA06
// -----------------------------------------------------------------------------
@@ -2530,6 +2576,47 @@
#define HLW8012_POWER_RATIO 3414290
#define HLW8012_INTERRUPT_ON FALLING
+// -----------------------------------------------------------------------------
+// Same as the above but new board version marked V2.3
+// -----------------------------------------------------------------------------
+
+#elif defined(BLITZWOLF_BWSHP2_V23)
+
+ // Info
+ #define MANUFACTURER "BLITZWOLF"
+ #define DEVICE "BWSHP2V2.3"
+
+ // Buttons
+ #define BUTTON1_PIN 3
+ #define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
+ #define BUTTON1_RELAY 1
+
+ // Relays
+ #define RELAY1_PIN 14
+ #define RELAY1_TYPE RELAY_TYPE_NORMAL
+
+ // LEDs
+ #define LED1_PIN 1
+ #define LED1_PIN_INVERSE 1
+ #define LED2_PIN 13
+ #define LED2_PIN_INVERSE 1
+ #define LED2_MODE LED_MODE_FINDME
+ #define LED2_RELAY 1
+
+ // HJL01 / BL0937
+ #ifndef HLW8012_SUPPORT
+ #define HLW8012_SUPPORT 1
+ #endif
+ #define HLW8012_SEL_PIN 12
+ #define HLW8012_CF1_PIN 5
+ #define HLW8012_CF_PIN 4
+
+ #define HLW8012_SEL_CURRENT LOW
+ #define HLW8012_CURRENT_RATIO 25740
+ #define HLW8012_VOLTAGE_RATIO 313400
+ #define HLW8012_POWER_RATIO 3414290
+ #define HLW8012_INTERRUPT_ON FALLING
+
// ----------------------------------------------------------------------------------------
// Homecube 16A is similar but some pins differ and it also has RGB LEDs
// https://www.amazon.de/gp/product/B07D7RVF56/ref=oh_aui_detailpage_o00_s01?ie=UTF8&psc=1
@@ -2896,6 +2983,7 @@
#define SI7021_SUPPORT 1
#define PMSX003_SUPPORT 1
#define SENSEAIR_SUPPORT1
+ #define VL53L1X_SUPPORT 1
// A bit of lights - pin 5
diff --git a/code/espurna/config/progmem.h b/code/espurna/config/progmem.h
index c4afe583..3fda6521 100644
--- a/code/espurna/config/progmem.h
+++ b/code/espurna/config/progmem.h
@@ -226,6 +226,9 @@ PROGMEM const char espurna_sensors[] =
#if VEML6075_SUPPORT
"VEML6075 "
#endif
+ #if VL53L1X_SUPPORT
+ "VL53L1X "
+ #endif
"";
diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h
index d8cf3430..3e3d3579 100644
--- a/code/espurna/config/prototypes.h
+++ b/code/espurna/config/prototypes.h
@@ -69,6 +69,8 @@ extern "C" {
#include
EEPROM_Rotate EEPROMr;
+void eepromSectorsDebug();
+
// -----------------------------------------------------------------------------
// GPIO
// -----------------------------------------------------------------------------
diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h
index ac11f82a..8681194a 100644
--- a/code/espurna/config/sensors.h
+++ b/code/espurna/config/sensors.h
@@ -115,6 +115,39 @@
#define BH1750_MODE BH1750_CONTINUOUS_HIGH_RES_MODE
+//------------------------------------------------------------------------------
+// VL53L1X
+// Enable support by passing VL53L1X_SUPPORT=1 build flag
+//------------------------------------------------------------------------------
+
+#ifndef VL53L1X_SUPPORT
+#define VL53L1X_SUPPORT 0
+#endif
+
+#ifndef VL53L1X_I2C_ADDRESS
+#define VL53L1X_I2C_ADDRESS 0x00 // 0x00 means auto
+#endif
+
+#ifndef VL53L1X_DISTANCE_MODE
+#define VL53L1X_DISTANCE_MODE VL53L1X::Long // The distance mode of the sensor. Can be one of
+#endif // `VL53L1X::Short`, `VL53L1X::Medium`, or `VL53L1X::Long.
+ // Shorter distance modes are less affected by ambient light
+ // but have lower maximum ranges, especially in the dark.
+
+
+#ifndef VL53L1X_MEASUREMENT_TIMING_BUDGET
+#define VL53L1X_MEASUREMENT_TIMING_BUDGET 140000 // The time, in microseconds, allocated for a single
+ // measurement. A longer timing budget allows for more
+ // accurate at the cost of power. The minimum budget is
+ // 20 ms (20000 us) in short distance mode and 33 ms for
+ // medium and long distance modes.
+#endif
+
+#ifndef VL53L1X_INTER_MEASUREMENT_PERIOD
+#define VL53L1X_INTER_MEASUREMENT_PERIOD 50 // Period, in milliseconds, determining how
+#endif // often the sensor takes a measurement.
+
+
//------------------------------------------------------------------------------
// BME280/BMP280
// Enable support by passing BMX280_SUPPORT=1 build flag
@@ -245,7 +278,7 @@
#define EMON_FILTER_SPEED 512 // Mobile average filter speed
#define EMON_MAINS_VOLTAGE 230 // Mains voltage
#define EMON_REFERENCE_VOLTAGE 3.3 // Reference voltage of the ADC
-#define EMON_CURRENT_RATIO 30 // Current ratio in the clamp (30V/1A)
+#define EMON_CURRENT_RATIO 30 // Current ratio in the clamp (30A/1V)
#define EMON_REPORT_CURRENT 0 // Report current
#define EMON_REPORT_POWER 1 // Report power
#define EMON_REPORT_ENERGY 1 // Report energy
@@ -600,6 +633,18 @@
#define PZEM004T_HW_PORT Serial // Hardware serial port (if PZEM004T_USE_SOFT == 0)
#endif
+#ifndef PZEM004T_ADDRESSES
+#define PZEM004T_ADDRESSES "192.168.1.1" // Device(s) address(es), separated by space, "192.168.1.1 192.168.1.2 192.168.1.3"
+#endif
+
+#ifndef PZEM004T_READ_INTERVAL
+#define PZEM004T_READ_INTERVAL 1500 // Read interval between same device
+#endif
+
+#ifndef PZEM004T_MAX_DEVICES
+#define PZEM004T_MAX_DEVICES 3
+#endif
+
//------------------------------------------------------------------------------
// SHT3X I2C (Wemos) temperature & humidity sensor
// Enable support by passing SHT3X_I2C_SUPPORT=1 build flag
@@ -744,7 +789,8 @@
SONAR_SUPPORT || \
TMP3X_SUPPORT || \
V9261F_SUPPORT || \
- VEML6075_SUPPORT \
+ VEML6075_SUPPORT || \
+ VL53L1X_SUPPORT \
)
#endif
@@ -906,4 +952,8 @@
#include "../sensors/VEML6075Sensor.h"
#endif
+#if VL53L1X_SUPPORT
+ #include "../sensors/VL53L1XSensor.h"
+#endif
+
#endif // SENSOR_SUPPORT
diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h
index ede6347b..8c258f83 100644
--- a/code/espurna/config/types.h
+++ b/code/espurna/config/types.h
@@ -280,6 +280,7 @@
#define SENSOR_MICS2710_ID 0x28
#define SENSOR_MICS5525_ID 0x29
#define SENSOR_VEML6075_ID 0x30
+#define SENSOR_VL53L1X_ID 0x31
//--------------------------------------------------------------------------------
// Magnitudes
diff --git a/code/espurna/debug.ino b/code/espurna/debug.ino
index 7eea7ccb..ba70ffee 100644
--- a/code/espurna/debug.ino
+++ b/code/espurna/debug.ino
@@ -209,6 +209,11 @@ void debugSetup() {
*/
extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack_start, uint32_t stack_end ) {
+ // Do not record crash data when resetting the board
+ if (checkNeedsReset()) {
+ return;
+ }
+
// This method assumes EEPROM has already been initialized
// which is the first thing ESPurna does
@@ -231,9 +236,13 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start);
EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end);
- // write stack trace to EEPROM
+ // starting address of Embedis data plus reserve
+ const uint16_t settings_start = SPI_FLASH_SEC_SIZE - settingsSize() - 0x10;
+
+ // write stack trace to EEPROM and avoid overwriting settings
int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE;
for (uint32_t i = stack_start; i < stack_end; i++) {
+ if (current_address >= settings_start) break;
byte* byteValue = (byte*) i;
EEPROMr.write(current_address++, *byteValue);
}
@@ -273,16 +282,23 @@ void debugDumpCrashInfo() {
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EPC3, epc3);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_EXCVADDR, excvaddr);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_DEPC, depc);
+
DEBUG_MSG_P(PSTR("[DEBUG] epc1=0x%08x epc2=0x%08x epc3=0x%08x\n"), epc1, epc2, epc3);
DEBUG_MSG_P(PSTR("[DEBUG] excvaddr=0x%08x depc=0x%08x\n"), excvaddr, depc);
uint32_t stack_start, stack_end;
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_START, stack_start);
EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_END, stack_end);
- DEBUG_MSG_P(PSTR("[DEBUG] >>>stack>>>\n[DEBUG] "));
+
+ DEBUG_MSG_P(PSTR("[DEBUG] sp=0x%08x end=0x%08x\n"), stack_start, stack_end);
+
int16_t current_address = SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_STACK_TRACE;
int16_t stack_len = stack_end - stack_start;
+
uint32_t stack_trace;
+
+ DEBUG_MSG_P(PSTR("[DEBUG] >>>stack>>>\n[DEBUG] "));
+
for (int16_t i = 0; i < stack_len; i += 0x10) {
DEBUG_MSG_P(PSTR("%08x: "), stack_start + i);
for (byte j = 0; j < 4; j++) {
diff --git a/code/espurna/eeprom.ino b/code/espurna/eeprom.ino
index ceee1868..ed1ad2b6 100644
--- a/code/espurna/eeprom.ino
+++ b/code/espurna/eeprom.ino
@@ -8,6 +8,11 @@ EEPROM MODULE
// -----------------------------------------------------------------------------
+bool _eeprom_commit = false;
+
+uint32_t _eeprom_commit_count = 0;
+bool _eeprom_last_commit_result = false;
+
void eepromRotate(bool value) {
// Enable/disable EEPROM rotation only if we are using more sectors than the
// reserved by the memory layout
@@ -34,15 +39,44 @@ String eepromSectors() {
return response;
}
+void eepromSectorsDebug() {
+ DEBUG_MSG_P(PSTR("[MAIN] EEPROM sectors: %s\n"), (char *) eepromSectors().c_str());
+ DEBUG_MSG_P(PSTR("[MAIN] EEPROM current: %lu\n"), eepromCurrent());
+}
+
+bool _eepromCommit() {
+ _eeprom_commit_count++;
+ _eeprom_last_commit_result = EEPROMr.commit();
+ return _eeprom_last_commit_result;
+}
+
+void eepromCommit() {
+ _eeprom_commit = true;
+}
+
#if TERMINAL_SUPPORT
void _eepromInitCommands() {
settingsRegisterCommand(F("EEPROM"), [](Embedis* e) {
infoMemory("EEPROM", SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE - settingsSize());
+ eepromSectorsDebug();
+ if (_eeprom_commit_count > 0) {
+ DEBUG_MSG_P(PSTR("[MAIN] Commits done: %lu\n"), _eeprom_commit_count);
+ DEBUG_MSG_P(PSTR("[MAIN] Last result: %s\n"), _eeprom_last_commit_result ? "OK" : "ERROR");
+ }
DEBUG_MSG_P(PSTR("+OK\n"));
});
+ settingsRegisterCommand(F("EEPROM.COMMIT"), [](Embedis* e) {
+ const bool res = _eepromCommit();
+ if (res) {
+ DEBUG_MSG_P(PSTR("+OK\n"));
+ } else {
+ DEBUG_MSG_P(PSTR("-ERROR\n"));
+ }
+ });
+
settingsRegisterCommand(F("EEPROM.DUMP"), [](Embedis* e) {
EEPROMr.dump(settingsSerial());
DEBUG_MSG_P(PSTR("\n+OK\n"));
@@ -69,6 +103,13 @@ void _eepromInitCommands() {
// -----------------------------------------------------------------------------
+void eepromLoop() {
+ if (_eeprom_commit) {
+ _eepromCommit();
+ _eeprom_commit = false;
+ }
+}
+
void eepromSetup() {
#ifdef EEPROM_ROTATE_SECTORS
@@ -92,4 +133,6 @@ void eepromSetup() {
_eepromInitCommands();
#endif
+ espurnaRegisterLoop(eepromLoop);
+
}
diff --git a/code/espurna/ir.ino b/code/espurna/ir.ino
index a61c8fc3..22f17bfa 100644
--- a/code/espurna/ir.ino
+++ b/code/espurna/ir.ino
@@ -43,8 +43,6 @@ Raw messages:
Payload: 1000,1000,1000,1000,1000
| IR codes |
- * To support long codes (Air Conditioneer) increase MQTT packet size -DMQTT_MAX_PACKET_SIZE=1200
-
--------------------------------------------------------------------------------
*/
@@ -91,7 +89,6 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
}
if (type == MQTT_MESSAGE_EVENT) {
-
String t = mqttMagnitude((char *) topic);
// Match topic
@@ -110,7 +107,7 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
_ir_repeat_size = 1;
// count & validate repeat-string
- for(int i = col+1; i < len; i++) {
+ for(unsigned int i = col+1; i < len; i++) {
if (i < len-1) {
if ( payload[i] == ',' && isDigit(payload[i+1]) && i>0 ) { //validate string
_ir_repeat_size++;
@@ -129,7 +126,7 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
} // end of counting & validating repeat code
// count & validate main code string
- for(int i = 0; i < len; i++) {
+ for(unsigned int i = 0; i < len; i++) {
if (i0 ) { //validate string
count++;
@@ -149,7 +146,7 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
int j = 0; // for populating values of array from comma separated string
// populating main code array from part of MQTT string
- for (int i = 0; i < len; i++) {
+ for (unsigned int i = 0; i < len; i++) {
if (payload[i] != ',') {
value = value + data[i];
}
@@ -173,14 +170,6 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
DEBUG_MSG_P(PSTR("[IR] Raw IR output %d codes, repeat %d times on %d(k)Hz freq.\n"), count, _ir_repeat, _ir_freq);
- /*
- DEBUG_MSG_P(PSTR("[IR] main codes: "));
- for(int i = 0; i < count; i++) {
- DEBUG_MSG_P(PSTR("%d,"),_ir_raw[i]);
- }
- DEBUG_MSG_P(PSTR("\n"));
- */
-
#if defined(IR_RX_PIN)
_ir_receiver.disableIRIn();
#endif
@@ -203,7 +192,7 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
len = data.length(); //redifining length to full lenght
// populating repeat code array from part of MQTT string
- for (int i = col+1; i < len; i++) {
+ for (unsigned int i = col+1; i < len; i++) {
value = value + data[i];
if ((payload[i] == ',') || (i == len - 1)) {
_ir_raw[j]= value.toInt();
@@ -211,7 +200,6 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
j++;
}
}
-
} else { // if repeat code not specified (col<=2) repeat with current main code
_ir_repeat_size = count;
}
@@ -223,7 +211,7 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
if (col > 0) {
_ir_type = data.toInt();
- _ir_code = data.substring(col+1).toInt();
+ _ir_code = strtoul(data.substring(col+1).c_str(), NULL, 10);
col = data.indexOf(":", col+1);
if (col > 0) {
@@ -234,9 +222,7 @@ void _irMqttCallback(unsigned int type, const char * topic, const char * payload
} else {
_ir_repeat = IR_REPEAT;
}
-
}
-
}
if (_ir_repeat > 0) {
@@ -364,12 +350,9 @@ void _irRXLoop() {
if (millis() - last_time < IR_DEBOUNCE) return;
last_time = millis();
- // Check code
- if (_ir_results.value < 1) return;
- if (_ir_results.decode_type < 1) return;
- if (_ir_results.bits < 1) return;
-
#if IR_USE_RAW
+ // Check code
+ if (_ir_results.rawlen < 1) return;
char * payload;
String value = "";
for (int i = 1; i < _ir_results.rawlen; i++) {
@@ -378,6 +361,10 @@ void _irRXLoop() {
}
payload = const_cast(value.c_str());
#else
+ // Check code
+ if (_ir_results.value < 1) return;
+ if (_ir_results.decode_type < 1) return;
+ if (_ir_results.bits < 1) return;
char payload[32];
snprintf_P(payload, sizeof(payload), PSTR("%u:%lu:%u"), _ir_results.decode_type, (unsigned long) _ir_results.value, _ir_results.bits);
#endif
diff --git a/code/espurna/migrate.ino b/code/espurna/migrate.ino
index 4e45cfec..008a943f 100644
--- a/code/espurna/migrate.ino
+++ b/code/espurna/migrate.ino
@@ -1223,6 +1223,16 @@ void migrate() {
setSetting("ledGPIO", 1, 15);
setSetting("ledLogic", 1, 0);
+ #elif defined(TONBUX_XSSSA01)
+
+ setSetting("board", 92);
+ setSetting("ledGPIO", 0, 13);
+ setSetting("ledLogic", 0, 0);
+ setSetting("btnGPIO", 0, 13);
+ setSetting("btnRelay", 0, 0);
+ setSetting("relayGPIO", 0, 5);
+ setSetting("relayType", 0, RELAY_TYPE_NORMAL);
+
#else
// Allow users to define new settings without migration config
diff --git a/code/espurna/mqtt.ino b/code/espurna/mqtt.ino
index bbd0e3d9..eef83bac 100644
--- a/code/espurna/mqtt.ino
+++ b/code/espurna/mqtt.ino
@@ -291,7 +291,7 @@ unsigned long _mqttNextMessageId() {
EEPROMr.write(EEPROM_MESSAGE_ID + 1, (id >> 16) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 2, (id >> 8) & 0xFF);
EEPROMr.write(EEPROM_MESSAGE_ID + 3, (id >> 0) & 0xFF);
- saveSettings();
+ eepromCommit();
}
id++;
diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino
index df01fbc4..acd3f36c 100644
--- a/code/espurna/relay.ino
+++ b/code/espurna/relay.ino
@@ -418,7 +418,7 @@ void relaySave(bool do_commit) {
// We are actually enqueuing the commit so it will be
// executed on the main loop, in case this is called from a callback
- saveSettings();
+ eepromCommit();
}
@@ -548,7 +548,7 @@ void _relayBoot() {
// Save if there is any relay in the RELAY_BOOT_TOGGLE mode
if (trigger_save) {
EEPROMr.write(EEPROM_RELAY_STATUS, mask);
- saveSettings();
+ eepromCommit();
}
_relayRecursive = false;
diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino
index ff7396f3..5dd16208 100644
--- a/code/espurna/sensor.ino
+++ b/code/espurna/sensor.ino
@@ -42,6 +42,10 @@ unsigned char _sensor_temperature_units = SENSOR_TEMPERATURE_UNITS;
double _sensor_temperature_correction = SENSOR_TEMPERATURE_CORRECTION;
double _sensor_humidity_correction = SENSOR_HUMIDITY_CORRECTION;
+#if PZEM004T_SUPPORT
+PZEM004TSensor *pzem004t_sensor;
+#endif
+
String _sensor_energy_reset_ts = String();
// -----------------------------------------------------------------------------
@@ -272,6 +276,63 @@ void _sensorInitCommands() {
}
DEBUG_MSG_P(PSTR("+OK\n"));
});
+ #if PZEM004T_SUPPORT
+ settingsRegisterCommand(F("PZ.ADDRESS"), [](Embedis* e) {
+ if (e->argc == 1) {
+ DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
+ unsigned char dev_count = pzem004t_sensor->getAddressesCount();
+ for(unsigned char dev = 0; dev < dev_count; dev++) {
+ DEBUG_MSG_P(PSTR("Device %d/%s\n"), dev, pzem004t_sensor->getAddress(dev).c_str());
+ }
+ DEBUG_MSG_P(PSTR("+OK\n"));
+ } else if(e->argc == 2) {
+ IPAddress addr;
+ if (addr.fromString(String(e->argv[1]))) {
+ if(pzem004t_sensor->setDeviceAddress(&addr)) {
+ DEBUG_MSG_P(PSTR("+OK\n"));
+ }
+ } else {
+ DEBUG_MSG_P(PSTR("-ERROR: Invalid address argument\n"));
+ }
+ } else {
+ DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
+ }
+ });
+ settingsRegisterCommand(F("PZ.RESET"), [](Embedis* e) {
+ if(e->argc > 2) {
+ DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
+ } else {
+ unsigned char init = e->argc == 2 ? String(e->argv[1]).toInt() : 0;
+ unsigned char limit = e->argc == 2 ? init +1 : pzem004t_sensor->getAddressesCount();
+ DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
+ for(unsigned char dev = init; dev < limit; dev++) {
+ float offset = pzem004t_sensor->resetEnergy(dev);
+ setSetting("pzEneTotal", dev, offset);
+ DEBUG_MSG_P(PSTR("Device %d/%s - Offset: %s\n"), dev, pzem004t_sensor->getAddress(dev).c_str(), String(offset).c_str());
+ }
+ DEBUG_MSG_P(PSTR("+OK\n"));
+ }
+ });
+ settingsRegisterCommand(F("PZ.VALUE"), [](Embedis* e) {
+ if(e->argc > 2) {
+ DEBUG_MSG_P(PSTR("-ERROR: Wrong arguments\n"));
+ } else {
+ unsigned char init = e->argc == 2 ? String(e->argv[1]).toInt() : 0;
+ unsigned char limit = e->argc == 2 ? init +1 : pzem004t_sensor->getAddressesCount();
+ DEBUG_MSG_P(PSTR("[SENSOR] PZEM004T\n"));
+ for(unsigned char dev = init; dev < limit; dev++) {
+ DEBUG_MSG_P(PSTR("Device %d/%s - Current: %s Voltage: %s Power: %s Energy: %s\n"), //
+ dev,
+ pzem004t_sensor->getAddress(dev).c_str(),
+ String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_CURRENT_INDEX)).c_str(),
+ String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_VOLTAGE_INDEX)).c_str(),
+ String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_POWER_ACTIVE_INDEX)).c_str(),
+ String(pzem004t_sensor->value(dev * PZ_MAGNITUDE_ENERGY_INDEX)).c_str());
+ }
+ DEBUG_MSG_P(PSTR("+OK\n"));
+ }
+ });
+ #endif
}
#endif
@@ -593,13 +654,20 @@ void _sensorLoad() {
#if PZEM004T_SUPPORT
{
- PZEM004TSensor * sensor = new PZEM004TSensor();
+ PZEM004TSensor * sensor = pzem004t_sensor = new PZEM004TSensor();
#if PZEM004T_USE_SOFT
sensor->setRX(PZEM004T_RX_PIN);
sensor->setTX(PZEM004T_TX_PIN);
#else
sensor->setSerial(& PZEM004T_HW_PORT);
#endif
+ sensor->setAddresses(PZEM004T_ADDRESSES);
+ // Read saved energy offset
+ unsigned char dev_count = sensor->getAddressesCount();
+ for(unsigned char dev = 0; dev < dev_count; dev++) {
+ float value = getSetting("pzEneTotal", dev, 0).toFloat();
+ if (value > 0) sensor->resetEnergy(dev, value);
+ }
_sensors.push_back(sensor);
}
#endif
@@ -644,6 +712,15 @@ void _sensorLoad() {
sensor->setDynamicMode(VEML6075_DYNAMIC_MODE);
_sensors.push_back(sensor);
}
+
+ #if VL53L1X_SUPPORT
+ {
+ VL53L1XSensor * sensor = new VL53L1XSensor();
+ sensor->setInterMeasurementPeriod(VL53L1X_INTER_MEASUREMENT_PERIOD);
+ sensor->setDistanceMode(VL53L1X_DISTANCE_MODE);
+ sensor->setMeasurementTimingBudget(VL53L1X_MEASUREMENT_TIMING_BUDGET);
+ _sensors.push_back(sensor);
+ }
#endif
}
@@ -978,6 +1055,22 @@ void _sensorConfigure() {
#endif // CSE7766_SUPPORT
+ #if PZEM004T_SUPPORT
+
+ if (_sensors[i]->getID() == SENSOR_PZEM004T_ID) {
+ PZEM004TSensor * sensor = (PZEM004TSensor *) _sensors[i];
+ if (getSetting("pwrResetE", 0).toInt() == 1) {
+ unsigned char dev_count = sensor->getAddressesCount();
+ for(unsigned char dev = 0; dev < dev_count; dev++) {
+ sensor->resetEnergy(dev, 0);
+ delSetting("pzEneTotal", dev);
+ }
+ _sensorResetTS();
+ }
+ }
+
+ #endif // PZEM004T_SUPPORT
+
}
// Update filter sizes
diff --git a/code/espurna/sensors/PMSX003Sensor.h b/code/espurna/sensors/PMSX003Sensor.h
index c117849d..54f8d0a5 100644
--- a/code/espurna/sensors/PMSX003Sensor.h
+++ b/code/espurna/sensors/PMSX003Sensor.h
@@ -90,7 +90,7 @@ class PMSX003 {
int avail = _serial->available();
#if SENSOR_DEBUG
- //debugSend("[SENSOR] PMS: Packet available = %d\n", avail);
+ //DEBUG_MSG("[SENSOR] PMS: Packet available = %d\n", avail);
#endif
if (avail < PMS_PACKET_SIZE(data_count)) {
break;
@@ -102,7 +102,7 @@ class PMSX003 {
uint16_t size = read16(sum);
if (size != PMS_PAYLOAD_SIZE(data_count)) {
#if SENSOR_DEBUG
- debugSend(("[SENSOR] PMS: Payload size: %d != %d.\n"), size, PMS_PAYLOAD_SIZE(data_count));
+ DEBUG_MSG(("[SENSOR] PMS: Payload size: %d != %d.\n"), size, PMS_PAYLOAD_SIZE(data_count));
#endif
break;
}
@@ -110,7 +110,7 @@ class PMSX003 {
for (int i = 0; i < data_count; i++) {
data[i] = read16(sum);
#if SENSOR_DEBUG
- //debugSend(("[SENSOR] PMS: data[%d] = %d\n"), i, data[i]);
+ //DEBUG_MSG(("[SENSOR] PMS: data[%d] = %d\n"), i, data[i]);
#endif
}
@@ -119,7 +119,7 @@ class PMSX003 {
return true;
} else {
#if SENSOR_DEBUG
- debugSend(("[SENSOR] PMS checksum: %04X != %04X\n"), sum, checksum);
+ DEBUG_MSG(("[SENSOR] PMS checksum: %04X != %04X\n"), sum, checksum);
#endif
}
break;
@@ -282,7 +282,7 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
readCycle = _readCount % 30;
if (readCycle == 0) {
#if SENSOR_DEBUG
- debugSend("[SENSOR] %s: Wake up: %d\n", pms_specs[_type].name, _readCount);
+ DEBUG_MSG("[SENSOR] %s: Wake up: %d\n", pms_specs[_type].name, _readCount);
#endif
wakeUp();
return;
@@ -321,7 +321,7 @@ class PMSX003Sensor : public BaseSensor, PMSX003 {
if (readCycle == 6) {
sleep();
#if SENSOR_DEBUG
- debugSend("[SENSOR] %s: Enter sleep mode: %d\n", pms_specs[_type].name, _readCount);
+ DEBUG_MSG("[SENSOR] %s: Enter sleep mode: %d\n", pms_specs[_type].name, _readCount);
#endif
return;
}
diff --git a/code/espurna/sensors/PZEM004TSensor.h b/code/espurna/sensors/PZEM004TSensor.h
index 57d5ba3e..8f5fda3f 100644
--- a/code/espurna/sensors/PZEM004TSensor.h
+++ b/code/espurna/sensors/PZEM004TSensor.h
@@ -3,6 +3,48 @@
// Copyright (C) 2018 by Xose Pérez
// -----------------------------------------------------------------------------
+// Connection Diagram:
+// -------------------
+//
+// Needed when connecting multiple PZEM004T devices on the same UART
+// *You must set the PZEM004T device address prior using this configuration*
+//
+// +---------+
+// | ESPurna | +VCC
+// | Node | ^
+// | G T R | |
+// +-+--+--+-+ R (10K)
+// | | | |
+// | | +-----------------+---------------+---------------+
+// | +-----------------+--|------------+--|------------+ |
+// +-----------------+--|--|---------+--|--|---------+ | |
+// | | | | | | | | |
+// | | V | | V | | V
+// | | - | | - | | -
+// +-+--+--+-+ +-+--+--+-+ +-+--+--+-+
+// | G R T | | G R T | | G R T |
+// |PZEM-004T| |PZEM-004T| |PZEM-004T|
+// | Module | | Module | | Module |
+// +---------+ +---------+ +---------+
+//
+// Where:
+// ------
+// G = GND
+// R = ESPurna UART RX
+// T = ESPurna UART TX
+// V = Small Signal Schottky Diode, like BAT43,
+// Cathode to PZEM TX, Anode to Espurna RX
+// R = Resistor to VCC, 10K
+//
+// More Info:
+// ----------
+// See ESPurna Wiki - https://github.com/xoseperez/espurna/wiki/Sensor-PZEM004T
+//
+// Reference:
+// ----------
+// UART/TTL-Serial network with single master and multiple slaves:
+// http://cool-emerald.blogspot.com/2009/10/multidrop-network-for-rs232.html
+
#if SENSOR_SUPPORT && PZEM004T_SUPPORT
#pragma once
@@ -12,6 +54,13 @@
#include
+#define PZ_MAGNITUDE_COUNT 4
+
+#define PZ_MAGNITUDE_CURRENT_INDEX 0
+#define PZ_MAGNITUDE_VOLTAGE_INDEX 1
+#define PZ_MAGNITUDE_POWER_ACTIVE_INDEX 2
+#define PZ_MAGNITUDE_ENERGY_INDEX 3
+
class PZEM004TSensor : public BaseSensor {
public:
@@ -21,9 +70,7 @@ class PZEM004TSensor : public BaseSensor {
// ---------------------------------------------------------------------
PZEM004TSensor(): BaseSensor() {
- _count = 4;
_sensor_id = SENSOR_PZEM004T_ID;
- _ip = IPAddress(192,168,1,1);
}
~PZEM004TSensor() {
@@ -49,6 +96,53 @@ class PZEM004TSensor : public BaseSensor {
_dirty = true;
}
+ // Set the devices physical addresses managed by this sensor
+ void setAddresses(const char *addresses) {
+ char const * sep = " ";
+ char tokens[strlen(addresses) + 1];
+ strlcpy(tokens, addresses, sizeof(tokens));
+ char *address = tokens;
+
+ int i = 0;
+ address = strtok(address, sep);
+ while (address != 0 && i++ < PZEM004T_MAX_DEVICES) {
+ IPAddress addr;
+ reading_t reading;
+ reading.current = PZEM_ERROR_VALUE;
+ reading.voltage = PZEM_ERROR_VALUE;
+ reading.power = PZEM_ERROR_VALUE;
+ reading.energy = PZEM_ERROR_VALUE;
+ if (addr.fromString(address)) {
+ _devices.push_back(addr);
+ _energy_offsets.push_back(0);
+ _readings.push_back(reading);
+ }
+ address = strtok(0, sep);
+ }
+ _count = _devices.size() * PZ_MAGNITUDE_COUNT;
+ _dirty = true;
+ }
+
+ // Return the number of devices managed by this sensor
+ unsigned char getAddressesCount() {
+ return _devices.size();
+ }
+
+ // Get device physical address based on the device index
+ String getAddress(unsigned char dev) {
+ return _devices[dev].toString();
+ }
+
+ // Set the device physical address
+ bool setDeviceAddress(IPAddress *addr) {
+ while(_busy) { yield(); };
+
+ _busy = true;
+ bool res = _pzem->setAddress(*addr);
+ _busy = false;
+ return res;
+ }
+
// ---------------------------------------------------------------------
unsigned char getRX() {
@@ -61,12 +155,11 @@ class PZEM004TSensor : public BaseSensor {
// ---------------------------------------------------------------------
- void resetEnergy(double value = 0) {
- if (_ready) {
- _energy_offset = value - (_pzem->energy(_ip) * 3600);
- } else {
- _energy_offset = value;
- }
+ // If called with value = -1, the offset will be the last energy reading
+ // otherwise, it will be the value provided
+ float resetEnergy(unsigned char dev, float value = -1) {
+ _energy_offsets[dev] = value != -1 ? value : _readings[dev].energy;
+ return _energy_offsets[dev];
}
// ---------------------------------------------------------------------
@@ -75,7 +168,6 @@ class PZEM004TSensor : public BaseSensor {
// Initialization method, must be idempotent
void begin() {
-
if (!_dirty) return;
if (_pzem) delete _pzem;
@@ -84,16 +176,15 @@ class PZEM004TSensor : public BaseSensor {
} else {
_pzem = new PZEM004T(_pin_rx, _pin_tx);
}
- _pzem->setAddress(_ip);
+ if(_devices.size() == 1) _pzem->setAddress(_devices[0]);
_ready = true;
_dirty = false;
-
}
// Descriptive name of the sensor
String description() {
- char buffer[28];
+ char buffer[27];
if (_serial) {
snprintf(buffer, sizeof(buffer), "PZEM004T @ HwSerial");
} else {
@@ -104,34 +195,99 @@ class PZEM004TSensor : public BaseSensor {
// Descriptive name of the slot # index
String slot(unsigned char index) {
- return description();
+ int dev = index / PZ_MAGNITUDE_COUNT;
+ char buffer[25];
+ snprintf(buffer, sizeof(buffer), "(%u/%s)", dev, getAddress(dev).c_str());
+ return description() + String(buffer);
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
- return _ip.toString();
+ int dev = index / PZ_MAGNITUDE_COUNT;
+ return _devices[dev].toString();
}
// Type for slot # index
unsigned char type(unsigned char index) {
- if (index == 0) return MAGNITUDE_CURRENT;
- if (index == 1) return MAGNITUDE_VOLTAGE;
- if (index == 2) return MAGNITUDE_POWER_ACTIVE;
- if (index == 3) return MAGNITUDE_ENERGY;
+ int dev = index / PZ_MAGNITUDE_COUNT;
+ index = index - (dev * PZ_MAGNITUDE_COUNT);
+ if (index == PZ_MAGNITUDE_CURRENT_INDEX) return MAGNITUDE_CURRENT;
+ if (index == PZ_MAGNITUDE_VOLTAGE_INDEX) return MAGNITUDE_VOLTAGE;
+ if (index == PZ_MAGNITUDE_POWER_ACTIVE_INDEX) return MAGNITUDE_POWER_ACTIVE;
+ if (index == PZ_MAGNITUDE_ENERGY_INDEX) return MAGNITUDE_ENERGY;
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) {
+ int dev = index / PZ_MAGNITUDE_COUNT;
+ index = index - (dev * PZ_MAGNITUDE_COUNT);
double response = 0;
- if (index == 0) response = _pzem->current(_ip);
- if (index == 1) response = _pzem->voltage(_ip);
- if (index == 2) response = _pzem->power(_ip);
- if (index == 3) response = _energy_offset + (_pzem->energy(_ip) * 3600);
+ if (index == PZ_MAGNITUDE_CURRENT_INDEX) response = _readings[dev].current;
+ if (index == PZ_MAGNITUDE_VOLTAGE_INDEX) response = _readings[dev].voltage;
+ if (index == PZ_MAGNITUDE_POWER_ACTIVE_INDEX) response = _readings[dev].power;
+ if (index == PZ_MAGNITUDE_ENERGY_INDEX) response = (_readings[dev].energy * 3600) - _energy_offsets[dev];
if (response < 0) response = 0;
return response;
}
+ // Post-read hook (usually to reset things)
+ void post() {
+ _error = SENSOR_ERROR_OK;
+ }
+
+ // Loop-like method, call it in your main loop
+ void tick() {
+ static unsigned char dev = 0;
+ static unsigned char magnitude = 0;
+ static unsigned long last_millis = 0;
+
+ if (_busy || millis() - last_millis < PZEM004T_READ_INTERVAL) return;
+
+ _busy = true;
+
+ // Clear buffer in case of late response(Timeout)
+ while(Serial.available() > 0) Serial.read();
+
+ float read;
+ float* readings_p;
+ switch(magnitude) {
+ case PZ_MAGNITUDE_CURRENT_INDEX:
+ read = _pzem->current(_devices[dev]);
+ readings_p = &_readings[dev].current;
+ break;
+ case PZ_MAGNITUDE_VOLTAGE_INDEX:
+ read = _pzem->voltage(_devices[dev]);
+ readings_p = &_readings[dev].voltage;
+ break;
+ case PZ_MAGNITUDE_POWER_ACTIVE_INDEX:
+ read = _pzem->power(_devices[dev]);
+ readings_p = &_readings[dev].power;
+ break;
+ case PZ_MAGNITUDE_ENERGY_INDEX:
+ read = _pzem->energy(_devices[dev]);
+ readings_p = &_readings[dev].energy;
+ break;
+ default:
+ _busy = false;
+ return;
+ }
+ if(read == PZEM_ERROR_VALUE) {
+ _error = SENSOR_ERROR_TIMEOUT;
+ } else {
+ *readings_p = read;
+ }
+
+ if(++dev == _devices.size()) {
+ dev = 0;
+ last_millis = millis();
+ if(++magnitude == PZ_MAGNITUDE_COUNT) {
+ magnitude = 0;
+ }
+ }
+ _busy = false;
+ }
+
protected:
// ---------------------------------------------------------------------
@@ -140,10 +296,18 @@ class PZEM004TSensor : public BaseSensor {
unsigned int _pin_rx = PZEM004T_RX_PIN;
unsigned int _pin_tx = PZEM004T_TX_PIN;
- IPAddress _ip;
+ bool _busy = false;
+ typedef struct {
+ float voltage;
+ float current;
+ float power;
+ float energy;
+ } reading_t;
+ std::vector _readings;
+ std::vector _energy_offsets;
+ std::vector _devices;
HardwareSerial * _serial = NULL;
PZEM004T * _pzem = NULL;
- double _energy_offset = 0;
};
diff --git a/code/espurna/sensors/VL53L1XSensor.h b/code/espurna/sensors/VL53L1XSensor.h
new file mode 100644
index 00000000..71bf6b7a
--- /dev/null
+++ b/code/espurna/sensors/VL53L1XSensor.h
@@ -0,0 +1,119 @@
+// -----------------------------------------------------------------------------
+// VL53L1X Sensor over I2C
+// Copyright (C) 2017-2018 by Xose Pérez
+// -----------------------------------------------------------------------------
+
+#if SENSOR_SUPPORT && VL53L1X_SUPPORT
+
+#pragma once
+
+#undef I2C_SUPPORT
+#define I2C_SUPPORT 1 // Explicitly request I2C support.
+
+
+#include "Arduino.h"
+#include "I2CSensor.h"
+#include "VL53L1X.h"
+
+class VL53L1XSensor : public I2CSensor {
+
+ public:
+
+ // ---------------------------------------------------------------------
+ // Public
+ // ---------------------------------------------------------------------
+
+ VL53L1XSensor(): I2CSensor() {
+ _count = 1;
+ _sensor_id = SENSOR_VL53L1X_ID;
+ _vl53l1x = new VL53L1X();
+ }
+
+ ~VL53L1XSensor() {
+ delete _vl53l1x;
+ }
+
+ // ---------------------------------------------------------------------
+
+ void setDistanceMode(VL53L1X::DistanceMode mode) {
+ _vl53l1x->setDistanceMode(mode);
+ }
+
+ void setMeasurementTimingBudget(uint32_t budget_us) {
+ _vl53l1x->setMeasurementTimingBudget(budget_us);
+ }
+
+ void setInterMeasurementPeriod(unsigned int period) {
+ if (_inter_measurement_period == period) return;
+ _inter_measurement_period = period;
+ _dirty = true;
+ }
+
+ // ---------------------------------------------------------------------
+ // Sensor API
+ // ---------------------------------------------------------------------
+
+ void begin() {
+ if (!_dirty) {
+ return;
+ }
+
+ // I2C auto-discover
+ unsigned char addresses[] = {0x29};
+ _address = _begin_i2c(_address, sizeof(addresses), addresses);
+ if (_address == 0) return;
+
+ _vl53l1x->setAddress(_address);
+
+ if (!_vl53l1x->init()) {
+ return;
+ };
+
+ _vl53l1x->startContinuous(_inter_measurement_period);
+
+ _ready = true;
+ _dirty = false;
+ }
+
+ // Descriptive name of the sensor
+ String description() {
+ char buffer[21];
+ snprintf(buffer, sizeof(buffer), "VL53L1X @ I2C (0x%02X)", _address);
+ return String(buffer);
+ }
+
+ // Descriptive name of the slot # index
+ String slot(unsigned char index) {
+ return description();
+ };
+
+ // Type for slot # index
+ unsigned char type(unsigned char index) {
+ if (index == 0) return MAGNITUDE_DISTANCE;
+ return MAGNITUDE_NONE;
+ }
+
+ // Pre-read hook (usually to populate registers with up-to-date data)
+ void pre() {
+ if (!_vl53l1x->dataReady()) {
+ return;
+ }
+
+ _distance = (double) _vl53l1x->read(false) / 1000.00;
+ }
+
+ // Current value for slot # index
+ double value(unsigned char index) {
+ if (index != 0) return 0;
+ return _distance;
+ }
+
+ protected:
+
+ VL53L1X * _vl53l1x = NULL;
+ unsigned int _inter_measurement_period;
+ double _distance = 0;
+
+};
+
+#endif // SENSOR_SUPPORT && VL53L1X_SUPPORT
diff --git a/code/espurna/settings.ino b/code/espurna/settings.ino
index 53657cab..6c545e85 100644
--- a/code/espurna/settings.ino
+++ b/code/espurna/settings.ino
@@ -22,8 +22,6 @@ EmbedisWrap embedis(_serial, TERMINAL_BUFFER_SIZE);
#endif // SERIAL_RX_ENABLED
#endif // TERMINAL_SUPPORT
-bool _settings_save = false;
-
// -----------------------------------------------------------------------------
// Reverse engineering EEPROM storage format
// -----------------------------------------------------------------------------
@@ -189,6 +187,7 @@ void _settingsInitCommands() {
settingsRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) {
DEBUG_MSG_P(PSTR("+OK\n"));
resetReason(CUSTOM_RESET_TERMINAL);
+ _eepromCommit();
ESP.eraseConfig();
*((int*) 0) = 0; // see https://github.com/esp8266/Arduino/issues/1494
});
@@ -310,7 +309,7 @@ void _settingsInitCommands() {
#if not SETTINGS_AUTOSAVE
settingsRegisterCommand(F("SAVE"), [](Embedis* e) {
- _settings_save = true;
+ eepromCommit();
DEBUG_MSG_P(PSTR("\n+OK\n"));
});
#endif
@@ -367,7 +366,7 @@ bool hasSetting(const String& key, unsigned int index) {
void saveSettings() {
#if not SETTINGS_AUTOSAVE
- _settings_save = true;
+ eepromCommit();
#endif
}
@@ -464,7 +463,7 @@ void settingsSetup() {
[](size_t pos) -> char { return EEPROMr.read(pos); },
[](size_t pos, char value) { EEPROMr.write(pos, value); },
#if SETTINGS_AUTOSAVE
- []() { _settings_save = true; }
+ []() { eepromCommit(); }
#else
[]() {}
#endif
@@ -485,12 +484,6 @@ void settingsSetup() {
void settingsLoop() {
- if (_settings_save) {
- EEPROMr.commit();
- _settings_save = false;
- }
-
-
#if TERMINAL_SUPPORT
#if DEBUG_SERIAL_SUPPORT
diff --git a/code/espurna/system.ino b/code/espurna/system.ino
index c988c6cd..6afd96b2 100644
--- a/code/espurna/system.ino
+++ b/code/espurna/system.ino
@@ -42,7 +42,7 @@ void systemCheck(bool stable) {
}
}
EEPROMr.write(EEPROM_CRASH_COUNTER, value);
- EEPROMr.commit();
+ eepromCommit();
}
bool systemCheck() {
@@ -77,6 +77,14 @@ unsigned long systemLoadAverage() {
void systemLoop() {
+ // -------------------------------------------------------------------------
+ // User requested reset
+ // -------------------------------------------------------------------------
+
+ if (checkNeedsReset()) {
+ reset();
+ }
+
// -------------------------------------------------------------------------
// Check system stability
// -------------------------------------------------------------------------
diff --git a/code/espurna/utils.ino b/code/espurna/utils.ino
index b5e838f4..cec21efc 100644
--- a/code/espurna/utils.ino
+++ b/code/espurna/utils.ino
@@ -9,6 +9,8 @@ Copyright (C) 2017-2018 by Xose Pérez
#include
Ticker _defer_reset;
+uint8_t _reset_reason = 0;
+
String getIdentifier() {
char buffer[20];
snprintf_P(buffer, sizeof(buffer), PSTR("%s-%06X"), APP_NAME, ESP.getChipId());
@@ -182,6 +184,9 @@ void heartbeat() {
#if (HEARTBEAT_REPORT_HOSTNAME)
mqttSend(MQTT_TOPIC_HOSTNAME, getSetting("hostname").c_str());
#endif
+ #if (HEARTBEAT_REPORT_SSID)
+ mqttSend(MQTT_TOPIC_SSID, WiFi.SSID().c_str());
+ #endif
#if (HEARTBEAT_REPORT_IP)
mqttSend(MQTT_TOPIC_IP, getIP().c_str());
#endif
@@ -347,8 +352,7 @@ void info() {
// -------------------------------------------------------------------------
- DEBUG_MSG_P(PSTR("[MAIN] EEPROM sectors: %s\n"), (char *) eepromSectors().c_str());
- DEBUG_MSG_P(PSTR("[MAIN] EEPROM current: %lu\n"), eepromCurrent());
+ eepromSectorsDebug();
DEBUG_MSG_P(PSTR("\n"));
// -------------------------------------------------------------------------
@@ -464,8 +468,9 @@ unsigned char resetReason() {
}
void resetReason(unsigned char reason) {
+ _reset_reason = reason;
EEPROMr.write(EEPROM_CUSTOM_RESET, reason);
- EEPROMr.commit();
+ eepromCommit();
}
void reset() {
@@ -473,8 +478,11 @@ void reset() {
}
void deferredReset(unsigned long delay, unsigned char reason) {
- resetReason(reason);
- _defer_reset.once_ms(delay, reset);
+ _defer_reset.once_ms(delay, resetReason, reason);
+}
+
+bool checkNeedsReset() {
+ return _reset_reason > 0;
}
// -----------------------------------------------------------------------------
diff --git a/code/html/custom.js b/code/html/custom.js
index 5eee06d1..3a9d6644 100644
--- a/code/html/custom.js
+++ b/code/html/custom.js
@@ -47,7 +47,7 @@ function sensorName(id) {
"Events", "PMSX003", "BMX280", "MHZ19", "SI7021",
"SHT3X I2C", "BH1750", "PZEM004T", "AM2320 I2C", "GUVAS12SD",
"TMP3X", "Sonar", "SenseAir", "GeigerTicks", "GeigerCPM",
- "NTC", "SDS011", "MICS2710", "MICS5525", "VEML6075"
+ "NTC", "SDS011", "MICS2710", "MICS5525", "VL53L1X", "VEML6075"
];
if (1 <= id && id <= names.length) {
return names[id - 1];
diff --git a/code/platformio.ini b/code/platformio.ini
index afaa9607..4685ec2f 100644
--- a/code/platformio.ini
+++ b/code/platformio.ini
@@ -98,6 +98,7 @@ lib_deps =
https://github.com/xoseperez/Time
NewPing
https://github.com/sparkfun/SparkFun_VEML6075_Arduino_Library#V_1.0.3
+ https://github.com/pololu/vl53l1x-arduino#1.0.1
lib_ignore =
# ------------------------------------------------------------------------------
@@ -2011,6 +2012,30 @@ upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags}
extra_scripts = ${common.extra_scripts}
+[env:maxcio-wde004]
+platform = ${common.platform}
+framework = ${common.framework}
+board = ${common.board_1m}
+board_build.flash_mode = ${common.flash_mode}
+lib_deps = ${common.lib_deps}
+lib_ignore = ${common.lib_ignore}
+build_flags = ${common.build_flags_1m0m} -DMAXCIO_WDE004
+monitor_speed = ${common.monitor_speed}
+extra_scripts = ${common.extra_scripts}
+
+[env:maxcio-wde004-ota]
+platform = ${common.platform}
+framework = ${common.framework}
+board = ${common.board_1m}
+board_build.flash_mode = ${common.flash_mode}
+lib_deps = ${common.lib_deps}
+lib_ignore = ${common.lib_ignore}
+build_flags = ${common.build_flags_1m0m} -DMAXCIO_WDE004
+upload_speed = ${common.upload_speed}
+upload_port = ${common.upload_port}
+upload_flags = ${common.upload_flags}
+extra_scripts = ${common.extra_scripts}
+
[env:yidian-xsssa05]
platform = ${common.platform}
framework = ${common.framework}
@@ -2035,6 +2060,31 @@ upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags}
extra_scripts = ${common.extra_scripts}
+[env:tonbux-xsssa01]
+platform = ${common.platform}
+framework = ${common.framework}
+board = ${common.board_1m}
+board_build.flash_mode = ${common.flash_mode}
+lib_deps = ${common.lib_deps}
+lib_ignore = ${common.lib_ignore}
+build_flags = ${common.build_flags_4m1m} -DTONBUX_XSSSA01
+upload_speed = ${common.upload_speed_fast}
+monitor_speed = ${common.monitor_speed}
+extra_scripts = ${common.extra_scripts}
+
+[env:tonbux-xsssa01-ota]
+platform = ${common.platform}
+framework = ${common.framework}
+board = ${common.board_1m}
+board_build.flash_mode = ${common.flash_mode}
+lib_deps = ${common.lib_deps}
+lib_ignore = ${common.lib_ignore}
+build_flags = ${common.build_flags_4m1m} -DTONBUX_XSSSA01
+upload_speed = ${common.upload_speed}
+upload_port = ${common.upload_port}
+upload_flags = ${common.upload_flags}
+extra_scripts = ${common.extra_scripts}
+
[env:tonbux-xsssa06]
platform = ${common.platform}
framework = ${common.framework}
@@ -2503,6 +2553,32 @@ upload_port = ${common.upload_port}
upload_flags = ${common.upload_flags}
extra_scripts = ${common.extra_scripts}
+[env:blitzwolf-bwshp2-v23]
+platform = ${common.platform}
+framework = ${common.framework}
+board = ${common.board_1m}
+board_build.flash_mode = ${common.flash_mode}
+lib_deps = ${common.lib_deps}
+lib_ignore = ${common.lib_ignore}
+build_flags = ${common.build_flags_1m0m} -DBLITZWOLF_BWSHP2_V23
+upload_speed = ${common.upload_speed}
+monitor_speed = ${common.monitor_speed}
+extra_scripts = ${common.extra_scripts}
+
+[env:blitzwolf-bwshp2-v23-ota]
+platform = ${common.platform}
+framework = ${common.framework}
+board = ${common.board_1m}
+board_build.flash_mode = ${common.flash_mode}
+lib_deps = ${common.lib_deps}
+lib_ignore = ${common.lib_ignore}
+build_flags = ${common.build_flags_1m0m} -DBLITZWOLF_BWSHP2_V23
+upload_speed = ${common.upload_speed}
+monitor_speed = ${common.monitor_speed}
+upload_port = ${common.upload_port}
+upload_flags = ${common.upload_flags}
+extra_scripts = ${common.extra_scripts}
+
[env:homecube-16a]
platform = ${common.platform}
framework = ${common.framework}
diff --git a/images/devices/tonbux-xs-ssa01.jpg b/images/devices/tonbux-xs-ssa01.jpg
new file mode 100644
index 00000000..a11fbf22
Binary files /dev/null and b/images/devices/tonbux-xs-ssa01.jpg differ