Browse Source

Merge branch 'dev' into power

Conflicts:
	code/espurna/config/sensors.h
	code/espurna/espurna.ino
fastled
Xose Pérez 7 years ago
parent
commit
da5a74a9c6
11 changed files with 538 additions and 138 deletions
  1. +4
    -2
      README.md
  2. +17
    -4
      code/espurna/config/general.h
  3. +27
    -1
      code/espurna/config/hardware.h
  4. +0
    -1
      code/espurna/espurna.ino
  5. +4
    -0
      code/espurna/hardware.ino
  6. +98
    -115
      code/espurna/mqtt.ino
  7. +3
    -3
      code/espurna/ota.ino
  8. +319
    -0
      code/espurna/v9261f.ino
  9. +9
    -6
      code/ota_flash.sh
  10. +9
    -6
      code/ota_list.sh
  11. +48
    -0
      code/platformio.ini

+ 4
- 2
README.md View File

@ -4,9 +4,11 @@ ESPurna ("spark" in Catalan) is a custom firmware for ESP8266 based smart switch
It was originally developed with the **[IteadStudio Sonoff](https://www.itead.cc/sonoff-wifi-wireless-switch.html)** in mind but now it supports a growing number of ESP8266-based boards. It was originally developed with the **[IteadStudio Sonoff](https://www.itead.cc/sonoff-wifi-wireless-switch.html)** in mind but now it supports a growing number of ESP8266-based boards.
It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries. It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
**Current Release Version is 1.9.3**, read the [changelog](https://bitbucket.org/xoseperez/espurna/src/master/CHANGELOG.md).
> **Current Release Version is 1.9.3**, read the [changelog](https://bitbucket.org/xoseperez/espurna/src/master/CHANGELOG.md).
**NOTE**: since version 1.9.0 the default **MQTT topics for commands have changed**. They all now end with "/set". This means you will have to change your controller software (Node-RED or alike) to send messages to -for instance- "/home/living/light/relay/0/set". The device will publish its state in "/home/living/light/relay/0" like before.
> **NOTICE**: Default flash layout changed in 1.8.3, as an unpredicted consequence devices will not be able to persist/retrieve configuration if flashed with 1.8.3 via **OTA** from **PlatformIO**. Please check issue #187.
> **NOTICE**: since version 1.9.0 the default **MQTT topics for commands have changed**. They all now end with "/set". This means you will have to change your controller software (Node-RED or alike) to send messages to -for instance- "/home/living/light/relay/0/set". The device will publish its state in "/home/living/light/relay/0" like before.
## Features ## Features


+ 17
- 4
code/espurna/config/general.h View File

@ -390,9 +390,11 @@ PROGMEM const char* const custom_reset_string[] = {
#define MQTT_RETAIN true // MQTT retain flag #define MQTT_RETAIN true // MQTT retain flag
#define MQTT_QOS 0 // MQTT QoS value for all messages #define MQTT_QOS 0 // MQTT QoS value for all messages
#define MQTT_KEEPALIVE 30 // MQTT keepalive value #define MQTT_KEEPALIVE 30 // MQTT keepalive value
#define MQTT_RECONNECT_DELAY 10000 // Try to reconnect after 10s
#define MQTT_TRY_INTERVAL 30000 // Timeframe for disconnect retries
#define MQTT_MAX_TRIES 5 // After these many retries during the previous MQTT_TRY_INTERVAL the board will reset
#define MQTT_RECONNECT_DELAY_MIN 5000 // Try to reconnect in 5 seconds upon disconnection
#define MQTT_RECONNECT_DELAY_STEP 5000 // Increase the reconnect delay in 5 seconds after each failed attempt
#define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most
#define MQTT_SKIP_RETAINED 1 // Skip retained messages on connection #define MQTT_SKIP_RETAINED 1 // Skip retained messages on connection
#define MQTT_SKIP_TIME 1000 // Skip messages for 1 second anter connection #define MQTT_SKIP_TIME 1000 // Skip messages for 1 second anter connection
@ -501,6 +503,7 @@ PROGMEM const char* const custom_reset_string[] = {
#define POWER_PROVIDER_EMON_ANALOG 0x10 #define POWER_PROVIDER_EMON_ANALOG 0x10
#define POWER_PROVIDER_EMON_ADC121 0x11 #define POWER_PROVIDER_EMON_ADC121 0x11
#define POWER_PROVIDER_HLW8012 0x20 #define POWER_PROVIDER_HLW8012 0x20
#define POWER_PROVIDER_V9261F 0x30
// Available magnitudes // Available magnitudes
#define POWER_MAGNITUDE_CURRENT 1 #define POWER_MAGNITUDE_CURRENT 1
@ -514,7 +517,7 @@ PROGMEM const char* const custom_reset_string[] = {
#endif #endif
// Identify available magnitudes // Identify available magnitudes
#if POWER_PROVIDER == POWER_PROVIDER_HLW8012
#if (POWER_PROVIDER == POWER_PROVIDER_HLW8012) || (POWER_PROVIDER == POWER_PROVIDER_V9261F)
#define POWER_HAS_ACTIVE 1 #define POWER_HAS_ACTIVE 1
#else #else
#define POWER_HAS_ACTIVE 0 #define POWER_HAS_ACTIVE 0
@ -526,6 +529,7 @@ PROGMEM const char* const custom_reset_string[] = {
#define POWER_SAMPLES 1000 #define POWER_SAMPLES 1000
#define POWER_INTERVAL 10000 #define POWER_INTERVAL 10000
#define POWER_REPORT_EVERY 6 #define POWER_REPORT_EVERY 6
#define POWER_REPORT_INTERVAL 60000
#define POWER_ENERGY_FACTOR (POWER_INTERVAL * POWER_REPORT_EVERY / 1000.0 / 3600.0) #define POWER_ENERGY_FACTOR (POWER_INTERVAL * POWER_REPORT_EVERY / 1000.0 / 3600.0)
#if POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG #if POWER_PROVIDER == POWER_PROVIDER_EMON_ANALOG
@ -553,6 +557,15 @@ PROGMEM const char* const custom_reset_string[] = {
#define HLW8012_VOLTAGE_R_DOWN ( 1000 ) // Real 1.009k #define HLW8012_VOLTAGE_R_DOWN ( 1000 ) // Real 1.009k
#endif #endif
#if POWER_PROVIDER == POWER_PROVIDER_V9261F
#define V9261F_SYNC_INTERVAL 600
#define V9261F_BAUDRATE 4800
#define V9261F_CURRENT_FACTOR 81156358
#define V9261F_VOLTAGE_FACTOR 4178508
#define V9261F_POWER_FACTOR 157859
#define V9261F_RPOWER_FACTOR V9261F_CURRENT_FACTOR
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// I2C // I2C
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 27
- 1
code/espurna/config/hardware.h View File

@ -77,9 +77,20 @@
// Buttons // Buttons
#define BUTTON1_PIN 4 #define BUTTON1_PIN 4
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1 #define BUTTON1_RELAY 1
// Normal pushbutton
//#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
// Touch button
#define BUTTON1_MODE BUTTON_PUSHBUTTON
#define BUTTON1_PRESS BUTTON_MODE_TOGGLE
#define BUTTON1_CLICK BUTTON_MODE_NONE
#define BUTTON1_DBLCLICK BUTTON_MODE_NONE
#define BUTTON1_LNGCLICK BUTTON_MODE_NONE
#define BUTTON1_LNGLNGCLICK BUTTON_MODE_NONE
// Relays // Relays
#define RELAY1_PIN 12 #define RELAY1_PIN 12
#define RELAY1_TYPE RELAY_TYPE_INVERSE #define RELAY1_TYPE RELAY_TYPE_INVERSE
@ -839,6 +850,21 @@
#define LIGHT_CH3_INVERSE 0 #define LIGHT_CH3_INVERSE 0
#define LIGHT_CH4_INVERSE 0 #define LIGHT_CH4_INVERSE 0
// -----------------------------------------------------------------------------
// V9261F
// -----------------------------------------------------------------------------
#elif defined(GENERIC_V9261F)
// Info
#define MANUFACTURER "GENERIC"
#define DEVICE "V9261F"
// V9261F
#define V9261F_SUPPORT 1
#define V9261F_PIN 2
#define V9261F_PIN_INVERSE 1
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Unknown hardware // Unknown hardware
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 0
- 1
code/espurna/espurna.ino View File

@ -220,7 +220,6 @@ void setup() {
setSetting("hostname", getIdentifier()); setSetting("hostname", getIdentifier());
} }
delay(500);
wifiSetup(); wifiSetup();
otaSetup(); otaSetup();
#if TELNET_SUPPORT #if TELNET_SUPPORT


+ 4
- 0
code/espurna/hardware.ino View File

@ -434,6 +434,10 @@ void hwUpwardsCompatibility() {
setSetting("chLogic", 4, 0); setSetting("chLogic", 4, 0);
setSetting("relays", 1); setSetting("relays", 1);
#elif defined(GENERIC_V9261F)
setSetting("board", 37);
#else #else
#error "UNSUPPORTED HARDWARE!" #error "UNSUPPORTED HARDWARE!"


+ 98
- 115
code/espurna/mqtt.ino View File

@ -31,7 +31,7 @@ WiFiClientSecure _mqtt_client_secure;
#endif // MQTT_USE_ASYNC #endif // MQTT_USE_ASYNC
bool _mqtt_enabled = MQTT_ENABLED; bool _mqtt_enabled = MQTT_ENABLED;
unsigned char _mqtt_connection_tries = 0;
unsigned long _mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
String _mqtt_topic; String _mqtt_topic;
String _mqtt_setter; String _mqtt_setter;
String _mqtt_getter; String _mqtt_getter;
@ -216,6 +216,7 @@ void _mqttCallback(unsigned int type, const char * topic, const char * payload)
void _mqttOnConnect() { void _mqttOnConnect() {
DEBUG_MSG_P(PSTR("[MQTT] Connected!\n")); DEBUG_MSG_P(PSTR("[MQTT] Connected!\n"));
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
#if MQTT_SKIP_RETAINED #if MQTT_SKIP_RETAINED
_mqtt_connected_at = millis(); _mqtt_connected_at = millis();
@ -316,137 +317,134 @@ bool mqttEnabled() {
void mqttConnect() { void mqttConnect() {
if (_mqtt_enabled & !_mqtt.connected()) {
// Disable MQTT after MQTT_MAX_TRIES attemps in a row
#if MQTT_MAX_TRIES > 0
static unsigned long last_try = millis();
if (millis() - last_try < MQTT_TRY_INTERVAL) {
if (++_mqtt_connection_tries > MQTT_MAX_TRIES) {
DEBUG_MSG_P(PSTR("[MQTT] MQTT_MAX_TRIES met, disabling MQTT\n"));
mqttEnabled(false);
_mqtt_connection_tries = 0;
return;
}
} else {
_mqtt_connection_tries = 0;
}
last_try = millis();
#endif
// Do not connect if disabled
if (!_mqtt_enabled) return;
if (_mqtt_user) free(_mqtt_user);
if (_mqtt_pass) free(_mqtt_pass);
// Do not connect if already connected
if (_mqtt.connected()) return;
char * host = strdup(getSetting("mqttServer", MQTT_SERVER).c_str());
if (strlen(host) == 0) return;
unsigned int port = getSetting("mqttPort", MQTT_PORT).toInt();
_mqtt_user = strdup(getSetting("mqttUser", MQTT_USER).c_str());
_mqtt_pass = strdup(getSetting("mqttPassword", MQTT_PASS).c_str());
if (_mqtt_will) free(_mqtt_will);
_mqtt_will = strdup((_mqtt_topic + MQTT_TOPIC_STATUS).c_str());
// Check reconnect interval
static unsigned long last = 0;
if (millis() - last < _mqtt_reconnect_delay) return;
last = millis();
DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%d\n"), host, port);
// Increase the reconnect delay
_mqtt_reconnect_delay += MQTT_RECONNECT_DELAY_STEP;
if (_mqtt_reconnect_delay > MQTT_RECONNECT_DELAY_MAX) {
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MAX;
}
#if MQTT_USE_ASYNC
char * host = strdup(getSetting("mqttServer", MQTT_SERVER).c_str());
if (strlen(host) == 0) return;
unsigned int port = getSetting("mqttPort", MQTT_PORT).toInt();
_mqtt.setServer(host, port);
_mqtt.setKeepAlive(MQTT_KEEPALIVE).setCleanSession(false);
_mqtt.setWill(_mqtt_will, MQTT_QOS, MQTT_RETAIN, "0");
if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) {
DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user);
_mqtt.setCredentials(_mqtt_user, _mqtt_pass);
}
if (_mqtt_user) free(_mqtt_user);
if (_mqtt_pass) free(_mqtt_pass);
if (_mqtt_will) free(_mqtt_will);
#if ASYNC_TCP_SSL_ENABLED
_mqtt_user = strdup(getSetting("mqttUser", MQTT_USER).c_str());
_mqtt_pass = strdup(getSetting("mqttPassword", MQTT_PASS).c_str());
_mqtt_will = strdup((_mqtt_topic + MQTT_TOPIC_STATUS).c_str());
bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1;
_mqtt.setSecure(secure);
if (secure) {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
unsigned char fp[20] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
_mqtt.addServerFingerprint(fp);
} else {
DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n"));
}
DEBUG_MSG_P(PSTR("[MQTT] Connecting to broker at %s:%d\n"), host, port);
#if MQTT_USE_ASYNC
_mqtt.setServer(host, port);
_mqtt.setKeepAlive(MQTT_KEEPALIVE).setCleanSession(false);
_mqtt.setWill(_mqtt_will, MQTT_QOS, MQTT_RETAIN, "0");
if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) {
DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user);
_mqtt.setCredentials(_mqtt_user, _mqtt_pass);
}
#if ASYNC_TCP_SSL_ENABLED
bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1;
_mqtt.setSecure(secure);
if (secure) {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
unsigned char fp[20] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
_mqtt.addServerFingerprint(fp);
} else {
DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n"));
} }
}
#endif // ASYNC_TCP_SSL_ENABLED
#endif // ASYNC_TCP_SSL_ENABLED
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), MQTT_QOS);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), MQTT_RETAIN);
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), MQTT_QOS);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), MQTT_RETAIN);
_mqtt.connect();
_mqtt.connect();
#else // not MQTT_USE_ASYNC
#else // not MQTT_USE_ASYNC
bool response = true;
bool response = true;
#if ASYNC_TCP_SSL_ENABLED
#if ASYNC_TCP_SSL_ENABLED
bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1;
if (secure) {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
if (_mqtt_client_secure.connect(host, port)) {
char fp[60] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (_mqtt_client_secure.verify(fp, host)) {
_mqtt.setClient(_mqtt_client_secure);
} else {
DEBUG_MSG_P(PSTR("[MQTT] Invalid fingerprint\n"));
response = false;
}
_mqtt_client_secure.stop();
yield();
bool secure = getSetting("mqttUseSSL", MQTT_SSL_ENABLED).toInt() == 1;
if (secure) {
DEBUG_MSG_P(PSTR("[MQTT] Using SSL\n"));
if (_mqtt_client_secure.connect(host, port)) {
char fp[60] = {0};
if (mqttFormatFP(getSetting("mqttFP", MQTT_SSL_FINGERPRINT).c_str(), fp)) {
if (_mqtt_client_secure.verify(fp, host)) {
_mqtt.setClient(_mqtt_client_secure);
} else { } else {
DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n"));
DEBUG_MSG_P(PSTR("[MQTT] Invalid fingerprint\n"));
response = false; response = false;
} }
_mqtt_client_secure.stop();
yield();
} else { } else {
DEBUG_MSG_P(PSTR("[MQTT] Client connection failed\n"));
DEBUG_MSG_P(PSTR("[MQTT] Wrong fingerprint\n"));
response = false; response = false;
} }
} else { } else {
_mqtt.setClient(_mqtt_client);
DEBUG_MSG_P(PSTR("[MQTT] Client connection failed\n"));
response = false;
} }
#else // not ASYNC_TCP_SSL_ENABLED
} else {
_mqtt.setClient(_mqtt_client); _mqtt.setClient(_mqtt_client);
}
#endif // ASYNC_TCP_SSL_ENABLED
if (response) {
#else // not ASYNC_TCP_SSL_ENABLED
_mqtt.setServer(host, port);
_mqtt.setClient(_mqtt_client);
if ((strlen(_mqtt_user) > 0) && (strlen(_mqtt_pass) > 0)) {
DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user);
response = _mqtt.connect(getIdentifier().c_str(), _mqtt_user, _mqtt_pass, _mqtt_will, MQTT_QOS, MQTT_RETAIN, "0");
} else {
response = _mqtt.connect(getIdentifier().c_str(), _mqtt_will, MQTT_QOS, MQTT_RETAIN, "0");
}
#endif // ASYNC_TCP_SSL_ENABLED
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), MQTT_QOS);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), MQTT_RETAIN);
if (response) {
}
_mqtt.setServer(host, port);
if (response) {
_mqttOnConnect();
_mqtt_connected = true;
if ((strlen(_mqtt_user) >> <span class="mi">0) && (strlen(_mqtt_pass) > 0)) {
DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user);
response = _mqtt.connect(getIdentifier().c_str(), _mqtt_user, _mqtt_pass, _mqtt_will, MQTT_QOS, MQTT_RETAIN, "0");
} else { } else {
DEBUG_MSG_P(PSTR("[MQTT] Connection failed\n"));
response = _mqtt.connect(getIdentifier().c_str(), _mqtt_will, MQTT_QOS, MQTT_RETAIN, "0");
} }
#endif // MQTT_USE_ASYNC
DEBUG_MSG_P(PSTR("[MQTT] Will topic: %s\n"), _mqtt_will);
DEBUG_MSG_P(PSTR("[MQTT] QoS: %d\n"), MQTT_QOS);
DEBUG_MSG_P(PSTR("[MQTT] Retain flag: %d\n"), MQTT_RETAIN);
}
if (response) {
_mqttOnConnect();
} else {
DEBUG_MSG_P(PSTR("[MQTT] Connection failed\n"));
}
free(host);
#endif // MQTT_USE_ASYNC
}
free(host);
} }
@ -463,7 +461,6 @@ void mqttConfigure() {
_mqtt_forward = !_mqtt_getter.equals(_mqtt_setter); _mqtt_forward = !_mqtt_getter.equals(_mqtt_setter);
// Enable // Enable
_mqtt_connection_tries = 0;
if (getSetting("mqttServer", MQTT_SERVER).length() == 0) { if (getSetting("mqttServer", MQTT_SERVER).length() == 0) {
mqttEnabled(false); mqttEnabled(false);
} else { } else {
@ -553,22 +550,14 @@ void mqttSetup() {
void mqttLoop() { void mqttLoop() {
#if MQTT_USE_ASYNC
if (WiFi.status() != WL_CONNECTED) return;
if (!_mqtt_enabled) return;
if (WiFi.status() != WL_CONNECTED) return;
if (_mqtt.connected()) return;
#if MQTT_USE_ASYNC
static unsigned long last = 0;
if (millis() - last > MQTT_RECONNECT_DELAY) {
last = millis();
mqttConnect();
}
mqttConnect();
#else // not MQTT_USE_ASYNC #else // not MQTT_USE_ASYNC
if (WiFi.status() != WL_CONNECTED) return;
if (_mqtt.connected()) { if (_mqtt.connected()) {
_mqtt.loop(); _mqtt.loop();
@ -580,13 +569,7 @@ void mqttLoop() {
_mqtt_connected = false; _mqtt_connected = false;
} }
if (_mqtt_enabled) {
static unsigned long last = 0;
if (millis() - last > MQTT_RECONNECT_DELAY) {
last = millis();
mqttConnect();
}
}
mqttConnect();
} }


+ 3
- 3
code/espurna/ota.ino View File

@ -56,9 +56,9 @@ void otaSetup() {
ArduinoOTA.begin(); ArduinoOTA.begin();
// Public ESPurna related txt for OTA discovery // Public ESPurna related txt for OTA discovery
MDNS.addServiceTxt("arduino", "tcp", "firmware", APP_NAME);
MDNS.addServiceTxt("arduino", "tcp", "espurna_version", APP_VERSION);
MDNS.addServiceTxt("arduino", "tcp", "espurna_board", DEVICE_NAME);
MDNS.addServiceTxt("arduino", "tcp", "app_name", APP_NAME);
MDNS.addServiceTxt("arduino", "tcp", "app_version", APP_VERSION);
MDNS.addServiceTxt("arduino", "tcp", "target_board", DEVICE_NAME);
} }


+ 319
- 0
code/espurna/v9261f.ino View File

@ -0,0 +1,319 @@
/*
V9261F MODULE
Support for V9261D-based power monitors
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
*/
/*
#if V9261F_SUPPORT
#include <SoftwareSerial.h>
#include <ArduinoJson.h>
SoftwareSerial * _v9261f_uart;
bool _v9261f_enabled = false;
bool _v9261f_ready = false;
bool _v9261f_newdata = false;
int _v9261f_power = 0;
int _v9261f_rpower = 0;
int _v9261f_voltage = 0;
double _v9261f_current = 0;
unsigned char _v9261f_data[24];
// -----------------------------------------------------------------------------
// PRIVATE
// -----------------------------------------------------------------------------
void v9261fRead() {
static unsigned char state = 0;
static unsigned long last = 0;
static bool found = false;
static unsigned char index = 0;
if (state == 0) {
while (_v9261f_uart->available()) {
_v9261f_uart->flush();
found = true;
last = millis();
}
if (found && (millis() - last > V9261F_SYNC_INTERVAL)) {
_v9261f_uart->flush();
index = 0;
state = 1;
}
} else if (state == 1) {
while (_v9261f_uart->available()) {
_v9261f_uart->read();
if (index++ >= 7) {
_v9261f_uart->flush();
index = 0;
state = 2;
}
}
} else if (state == 2) {
while (_v9261f_uart->available()) {
_v9261f_data[index] = _v9261f_uart->read();
if (index++ >= 19) {
_v9261f_uart->flush();
last = millis();
state = 3;
}
}
} else if (state == 3) {
/*
for (unsigned char i=0; i<index;i++) {
DEBUG_MSG("%02X ", _v9261f_data[i]);
}
DEBUG_MSG("\n");
*/
if (checksumOK()) {
_v9261f_power = (double) (
(_v9261f_data[3]) +
(_v9261f_data[4] << 8) +
(_v9261f_data[5] << 16) +
(_v9261f_data[6] << 24)
) / V9261F_POWER_FACTOR;
_v9261f_rpower = (double) (
(_v9261f_data[7]) +
(_v9261f_data[8] << 8) +
(_v9261f_data[9] << 16) +
(_v9261f_data[10] << 24)
) / V9261F_RPOWER_FACTOR;
_v9261f_voltage = (double) (
(_v9261f_data[11]) +
(_v9261f_data[12] << 8) +
(_v9261f_data[13] << 16) +
(_v9261f_data[14] << 24)
) / V9261F_VOLTAGE_FACTOR;
_v9261f_current = (double) (
(_v9261f_data[15]) +
(_v9261f_data[16] << 8) +
(_v9261f_data[17] << 16) +
(_v9261f_data[18] << 24)
) / V9261F_CURRENT_FACTOR;
_v9261f_newdata = true;
/*
DEBUG_MSG_P(PSTR("[V9261F] W = %lu\n"), _v9261f_power);
DEBUG_MSG_P(PSTR("[V9261F] R = %lu\n"), _v9261f_rpower);
DEBUG_MSG_P(PSTR("[V9261F] V = %lu\n"), _v9261f_voltage);
DEBUG_MSG_P(PSTR("[V9261F] C = %lu\n"), _v9261f_current);
*/
}
last = millis();
index = 0;
state = 4;
} else if (state == 4) {
while (_v9261f_uart->available()) {
_v9261f_uart->flush();
last = millis();
}
if (millis() - last > V9261F_SYNC_INTERVAL) {
state = 1;
}
}
}
boolean checksumOK() {
unsigned char checksum = 0;
for (unsigned char i = 0; i < 19; i++) {
checksum = checksum + _v9261f_data[i];
}
checksum = ~checksum + 0x33;
return checksum == _v9261f_data[19];
}
// -----------------------------------------------------------------------------
// HAL
// -----------------------------------------------------------------------------
unsigned int getActivePower() {
return _v9261f_power;
}
unsigned int getReactivePower() {
return _v9261f_rpower;
}
unsigned int getApparentPower() {
return sqrt(_v9261f_rpower * _v9261f_rpower + _v9261f_power * _v9261f_power);
}
unsigned int getVoltage() {
return _v9261f_voltage;
}
double getCurrent() {
return _v9261f_current;
}
double getPowerFactor() {
unsigned int apparent = getApparentPower();
if (apparent > 0) return getActivePower() / getApparentPower();
return 1;
}
// -----------------------------------------------------------------------------
void v9261fSetup() {
_v9261f_uart = new SoftwareSerial(V9261F_PIN, SW_SERIAL_UNUSED_PIN, V9261F_PIN_INVERSE, 256);
_v9261f_uart->begin(V9261F_BAUDRATE);
// API definitions
#if WEB_SUPPORT
apiRegister(HLW8012_POWER_TOPIC, HLW8012_POWER_TOPIC, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), _v9261f_power);
});
apiRegister(HLW8012_CURRENT_TOPIC, HLW8012_CURRENT_TOPIC, [](char * buffer, size_t len) {
dtostrf(_v9261f_current, len-1, 3, buffer);
});
apiRegister(HLW8012_VOLTAGE_TOPIC, HLW8012_VOLTAGE_TOPIC, [](char * buffer, size_t len) {
snprintf_P(buffer, len, PSTR("%d"), _v9261f_voltage);
});
#endif // WEB_SUPPORT
}
void v9261fLoop() {
static int sum_power = 0;
static int sum_rpower = 0;
static int sum_voltage = 0;
static double sum_current = 0;
static int count = 0;
// Sniff data in the UART interface
v9261fRead();
// Do we have new data?
if (_v9261f_newdata) {
_v9261f_newdata = false;
sum_power += getActivePower();
sum_rpower += getReactivePower();
sum_voltage += getVoltage();
sum_current += getCurrent();
count++;
#if WEB_SUPPORT
{
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
char buf_current[10];
dtostrf(getCurrent(), 6, 3, buf_current);
root["powVisible"] = 1;
root["powActivePower"] = getActivePower();
root["powCurrent"] = String(ltrim(buf_current));
root["powVoltage"] = getVoltage();
root["powApparentPower"] = getApparentPower();
root["powReactivePower"] = getReactivePower();
root["powPowerFactor"] = 100 * getPowerFactor();
String output;
root.printTo(output);
wsSend(output.c_str());
}
#endif
}
// Do we have to report?
static unsigned long last = 0;
if ((count == 0) || (millis() - last < V9261F_REPORT_INTERVAL)) return;
last = millis();
{
unsigned int power = sum_power / count;
unsigned int reactive = sum_rpower / count;
unsigned int voltage = sum_voltage / count;
double current = sum_current / count;
char buf_current[10];
dtostrf(current, 6, 3, buf_current);
unsigned int apparent = sqrt(power * power + reactive * reactive);
double energy_delta = (double) power * V9261F_REPORT_INTERVAL / 1000.0 / 3600.0;
char buf_energy[10];
dtostrf(energy_delta, 6, 3, buf_energy);
unsigned int factor = 100 * ((double) power / apparent);
// Report values to MQTT broker
mqttSend(HLW8012_POWER_TOPIC, String(power).c_str());
mqttSend(HLW8012_CURRENT_TOPIC, buf_current);
mqttSend(HLW8012_VOLTAGE_TOPIC, String(voltage).c_str());
mqttSend(HLW8012_ENERGY_TOPIC, buf_energy);
mqttSend(HLW8012_APOWER_TOPIC, String(apparent).c_str());
mqttSend(HLW8012_RPOWER_TOPIC, String(reactive).c_str());
mqttSend(HLW8012_PFACTOR_TOPIC, String(factor).c_str());
// Report values to Domoticz
#if DOMOTICZ_SUPPORT
{
char buffer[20];
snprintf_P(buffer, sizeof(buffer), PSTR("%d;%s"), power, buf_energy);
domoticzSend("dczPowIdx", 0, buffer);
snprintf_P(buffer, sizeof(buffer), PSTR("%s"), buf_energy);
domoticzSend("dczEnergyIdx", 0, buffer);
snprintf_P(buffer, sizeof(buffer), PSTR("%d"), voltage);
domoticzSend("dczVoltIdx", 0, buffer);
snprintf_P(buffer, sizeof(buffer), PSTR("%s"), buf_current);
domoticzSend("dczCurrentIdx", 0, buffer);
}
#endif
#if INFLUXDB_SUPPORT
{
influxDBSend(HLW8012_POWER_TOPIC, String(power).c_str());
influxDBSend(HLW8012_CURRENT_TOPIC, buf_current);
influxDBSend(HLW8012_VOLTAGE_TOPIC, String(voltage).c_str());
influxDBSend(HLW8012_ENERGY_TOPIC, buf_energy);
influxDBSend(HLW8012_APOWER_TOPIC, String(apparent).c_str());
influxDBSend(HLW8012_RPOWER_TOPIC, String(reactive).c_str());
influxDBSend(HLW8012_PFACTOR_TOPIC, String(factor).c_str());
}
#endif
// Reset counters
sum_power = sum_rpower = sum_voltage = sum_current = count = 0;
}
}
#endif
*/

+ 9
- 6
code/ota_flash.sh View File

@ -24,11 +24,12 @@ useAvahi() {
echo_pad "#" 4 echo_pad "#" 4
echo_pad "HOSTNAME" 20 echo_pad "HOSTNAME" 20
echo_pad "IP" 20 echo_pad "IP" 20
echo_pad "APP" 15
echo_pad "VERSION" 15
echo_pad "DEVICE" 30 echo_pad "DEVICE" 30
echo_pad "VERSION" 10
echo echo
printf -v line '%*s\n' 84
printf -v line '%*s\n' 104
echo ${line// /-} echo ${line// /-}
counter=0 counter=0
@ -40,7 +41,7 @@ useAvahi() {
echo -n "" > $board_file echo -n "" > $board_file
echo -n "$counter" > $count_file echo -n "$counter" > $count_file
avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | while read line; do
avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | sort -t ';' -k 3 | while read line; do
(( counter++ )) (( counter++ ))
echo "$counter" > $count_file echo "$counter" > $count_file
@ -48,8 +49,9 @@ useAvahi() {
hostname=`echo $line | cut -d ';' -f4` hostname=`echo $line | cut -d ';' -f4`
ip=`echo $line | cut -d ';' -f8` ip=`echo $line | cut -d ';' -f8`
txt=`echo $line | cut -d ';' -f10` txt=`echo $line | cut -d ';' -f10`
board=`echo $txt | sed -n "s/.*espurna_board=\([^\"]*\).*/\1/p"`
version=`echo $txt | sed -n "s/.*espurna_version=\([^\"]*\).*/\1/p"`
app_name=`echo $txt | sed -n "s/.*app_name=\([^\"]*\).*/\1/p"`
app_version=`echo $txt | sed -n "s/.*app_version=\([^\"]*\).*/\1/p"`
board=`echo $txt | sed -n "s/.*target_board=\([^\"]*\).*/\1/p"`
echo -n "$ip;" >> $ip_file echo -n "$ip;" >> $ip_file
echo -n "$board;" >> $board_file echo -n "$board;" >> $board_file
@ -57,8 +59,9 @@ useAvahi() {
echo_pad "$counter" 4 echo_pad "$counter" 4
echo_pad "$hostname" 20 echo_pad "$hostname" 20
echo_pad "$ip" 20 echo_pad "$ip" 20
echo_pad "$app_name" 15
echo_pad "$app_version" 15
echo_pad "$board" 30 echo_pad "$board" 30
echo_pad "$version" 10
echo echo


+ 9
- 6
code/ota_list.sh View File

@ -16,30 +16,33 @@ useAvahi() {
echo_pad "#" 4 echo_pad "#" 4
echo_pad "HOSTNAME" 20 echo_pad "HOSTNAME" 20
echo_pad "IP" 20 echo_pad "IP" 20
echo_pad "APP" 15
echo_pad "VERSION" 15
echo_pad "DEVICE" 30 echo_pad "DEVICE" 30
echo_pad "VERSION" 10
echo echo
printf -v line '%*s\n' 84
printf -v line '%*s\n' 104
echo ${line// /-} echo ${line// /-}
counter=0 counter=0
avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | while read line; do
avahi-browse -t -r -p "_arduino._tcp" 2>/dev/null | grep ^= | sort -t ';' -k 3 | while read line; do
(( counter++ )) (( counter++ ))
hostname=`echo $line | cut -d ';' -f4` hostname=`echo $line | cut -d ';' -f4`
ip=`echo $line | cut -d ';' -f8` ip=`echo $line | cut -d ';' -f8`
txt=`echo $line | cut -d ';' -f10` txt=`echo $line | cut -d ';' -f10`
board=`echo $txt | sed -n "s/.*espurna_board=\([^\"]*\).*/\1/p"`
version=`echo $txt | sed -n "s/.*espurna_version=\([^\"]*\).*/\1/p"`
app_name=`echo $txt | sed -n "s/.*app_name=\([^\"]*\).*/\1/p"`
app_version=`echo $txt | sed -n "s/.*app_version=\([^\"]*\).*/\1/p"`
board=`echo $txt | sed -n "s/.*target_board=\([^\"]*\).*/\1/p"`
echo_pad "$counter" 4 echo_pad "$counter" 4
echo_pad "$hostname" 20 echo_pad "$hostname" 20
echo_pad "$ip" 20 echo_pad "$ip" 20
echo_pad "$app_name" 15
echo_pad "$app_version" 15
echo_pad "$board" 30 echo_pad "$board" 30
echo_pad "$version" 10
echo echo
done done


+ 48
- 0
code/platformio.ini View File

@ -22,6 +22,7 @@ lib_deps =
OneWire OneWire
DallasTemperature DallasTemperature
Brzo I2C Brzo I2C
EspSoftwareSerial
https://bitbucket.org/xoseperez/justwifi.git#1.1.4 https://bitbucket.org/xoseperez/justwifi.git#1.1.4
https://bitbucket.org/xoseperez/hlw8012.git#1.0.1 https://bitbucket.org/xoseperez/hlw8012.git#1.0.1
https://bitbucket.org/xoseperez/fauxmoesp.git#2.2.0 https://bitbucket.org/xoseperez/fauxmoesp.git#2.2.0
@ -683,6 +684,7 @@ monitor_baud = 115200
platform = espressif8266 platform = espressif8266
framework = arduino framework = arduino
board = esp01_1m board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps} lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore} lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER
@ -692,6 +694,7 @@ monitor_baud = 115200
platform = espressif8266 platform = espressif8266
framework = arduino framework = arduino
board = esp01_1m board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps} lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore} lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER build_flags = ${common.build_flags_1m} -DMAGICHOME_LED_CONTROLLER
@ -815,6 +818,51 @@ upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266 upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200 monitor_baud = 115200
[env:wemos-v9261f]
platform = espressif8266
framework = arduino
board = d1_mini
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DGENERIC_V9261F
upload_speed = 460800
monitor_baud = 115200
[env:wemos-v9261f-ota]
platform = espressif8266
framework = arduino
board = d1_mini
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags} -DGENERIC_V9261F
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
[env:esp01-v9261f]
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DGENERIC_V9261F
monitor_baud = 115200
[env:esp01-v9261f-ota]
platform = espressif8266
framework = arduino
board = esp01_1m
board_flash_mode = dout
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
build_flags = ${common.build_flags_1m} -DGENERIC_V9261F
upload_speed = 115200
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# GENERIC OTA ENVIRONMENTS # GENERIC OTA ENVIRONMENTS
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------


Loading…
Cancel
Save