Browse Source

Preliminary support for CSE7766 (Sonoff S31 & Sonoff POW R2)

rfm69
Xose Pérez 6 years ago
parent
commit
0e6f2d1ca3
10 changed files with 2384 additions and 2025 deletions
  1. +3
    -3
      README.md
  2. +1
    -0
      code/espurna/config/arduino.h
  3. +27
    -0
      code/espurna/config/hardware.h
  4. +32
    -1
      code/espurna/config/sensors.h
  5. BIN
      code/espurna/data/index.html.gz
  6. +2
    -0
      code/espurna/sensors/BaseSensor.h
  7. +273
    -0
      code/espurna/sensors/CSE7766Sensor.h
  8. +2021
    -2020
      code/espurna/static/index.html.gz.h
  9. +1
    -1
      code/html/custom.js
  10. +24
    -0
      code/platformio.ini

+ 3
- 3
README.md View File

@ -4,9 +4,9 @@ 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. It uses the Arduino Core for ESP8266 framework and a number of 3rd party libraries.
[![version](https://img.shields.io/badge/version-1.12.5b-brightgreen.svg)](CHANGELOG.md) [![version](https://img.shields.io/badge/version-1.12.5b-brightgreen.svg)](CHANGELOG.md)
![branch](https://img.shields.io/badge/branch-dev-orange.svg)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=dev)](https://travis-ci.org/xoseperez/espurna)
[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/dev.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard)
![branch](https://img.shields.io/badge/branch-sensors-orange.svg)
[![travis](https://travis-ci.org/xoseperez/espurna.svg?branch=sensors)](https://travis-ci.org/xoseperez/espurna)
[![codacy](https://img.shields.io/codacy/grade/c9496e25cf07434cba786b462cb15f49/sensors.svg)](https://www.codacy.com/app/xoseperez/espurna/dashboard)
[![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE) [![license](https://img.shields.io/github/license/xoseperez/espurna.svg)](LICENSE)
<br /> <br />
[![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&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest) [![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&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest)


+ 1
- 0
code/espurna/config/arduino.h View File

@ -32,6 +32,7 @@
//#define ITEAD_SONOFF_T1_1CH //#define ITEAD_SONOFF_T1_1CH
//#define ITEAD_SONOFF_T1_2CH //#define ITEAD_SONOFF_T1_2CH
//#define ITEAD_SONOFF_T1_3CH //#define ITEAD_SONOFF_T1_3CH
//#define ITEAD_SONOFF_S31
//#define YJZK_SWITCH_2CH //#define YJZK_SWITCH_2CH
//#define ELECTRODRAGON_WIFI_IOT //#define ELECTRODRAGON_WIFI_IOT
//#define WORKCHOICE_ECOPLUG //#define WORKCHOICE_ECOPLUG


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

@ -768,6 +768,33 @@
#define LED1_PIN 13 #define LED1_PIN 13
#define LED1_PIN_INVERSE 1 #define LED1_PIN_INVERSE 1
#elif defined(ITEAD_SONOFF_S31)
// Info
#define MANUFACTURER "ITEAD"
#define DEVICE "SONOFF_S31"
// Buttons
#define BUTTON1_PIN 0
#define BUTTON1_MODE BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_RELAY 1
// Relays
#define RELAY1_PIN 12
#define RELAY1_TYPE RELAY_TYPE_NORMAL
// LEDs
#define LED1_PIN 13
#define LED1_PIN_INVERSE 1
// Disable UART noise
#define TERMINAL_SUPPORT 0
#define DEBUG_SERIAL_SUPPORT 0
// CSE7766
#define CSE7766_SUPPORT 1
#define CSE7766_PIN 1
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// YJZK // YJZK
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 32
- 1
code/espurna/config/sensors.h View File

@ -108,6 +108,7 @@
#define SENSOR_PZEM004T_ID 0x18 #define SENSOR_PZEM004T_ID 0x18
#define SENSOR_AM2320_ID 0x19 #define SENSOR_AM2320_ID 0x19
#define SENSOR_GUVAS12SD_ID 0x20 #define SENSOR_GUVAS12SD_ID 0x20
#define SENSOR_CSE7766_ID 0x21
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// Magnitudes // Magnitudes
@ -236,6 +237,30 @@
#define DHT_TYPE DHT_CHIP_DHT22 #define DHT_TYPE DHT_CHIP_DHT22
#endif #endif
//------------------------------------------------------------------------------
// CSE7766 based power sensor
// Enable support by passing CSE7766_SUPPORT=1 build flag
//------------------------------------------------------------------------------
#ifndef CSE7766_SUPPORT
#define CSE7766_SUPPORT 1
#endif
#ifndef CSE7766_PIN
#define CSE7766_PIN 1 // TX pin from the CSE7766
#endif
#ifndef CSE7766_PIN_INVERSE
#define CSE7766_PIN_INVERSE 0 // Signal is inverted
#endif
#define CSE7766_SYNC_INTERVAL 300 // Safe time between transmissions (ms)
#define CSE7766_BAUDRATE 4800 // UART baudrate
#define CSE7766_V1R 1.0 // 1mR current resistor
#define CSE7766_V2R 1.0 // 1M voltage resistor
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Digital sensor // Digital sensor
// Enable support by passing DIGITAL_SUPPORT=1 build flag // Enable support by passing DIGITAL_SUPPORT=1 build flag
@ -556,7 +581,8 @@
|| EMON_ADC121_SUPPORT || EMON_ADS1X15_SUPPORT \ || EMON_ADC121_SUPPORT || EMON_ADS1X15_SUPPORT \
|| EMON_ANALOG_SUPPORT || EVENTS_SUPPORT || HLW8012_SUPPORT \ || EMON_ANALOG_SUPPORT || EVENTS_SUPPORT || HLW8012_SUPPORT \
|| MHZ19_SUPPORT || PMSX003_SUPPORT || SHT3X_I2C_SUPPORT \ || MHZ19_SUPPORT || PMSX003_SUPPORT || SHT3X_I2C_SUPPORT \
|| SI7021_SUPPORT || V9261F_SUPPORT || AM2320_SUPPORT || GUVAS12SD_SUPPORT
|| SI7021_SUPPORT || V9261F_SUPPORT || AM2320_SUPPORT \
|| GUVAS12SD_SUPPORT || CSE7766_SUPPORT
#define SENSOR_SUPPORT 1 #define SENSOR_SUPPORT 1
#else #else
#define SENSOR_SUPPORT 0 #define SENSOR_SUPPORT 0
@ -687,6 +713,11 @@ PROGMEM const char* const magnitude_units[] = {
#include "../sensors/BMX280Sensor.h" #include "../sensors/BMX280Sensor.h"
#endif #endif
#if CSE7766_SUPPORT
#include <SoftwareSerial.h>
#include "../sensors/CSE7766Sensor.h"
#endif
#if DALLAS_SUPPORT #if DALLAS_SUPPORT
#include <OneWire.h> #include <OneWire.h>
#include "../sensors/DallasSensor.h" #include "../sensors/DallasSensor.h"


BIN
code/espurna/data/index.html.gz View File


+ 2
- 0
code/espurna/sensors/BaseSensor.h View File

@ -18,6 +18,8 @@
#define SENSOR_ERROR_CRC 5 // Sensor data corrupted #define SENSOR_ERROR_CRC 5 // Sensor data corrupted
#define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address #define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address
#define SENSOR_ERROR_GPIO_USED 7 // The GPIO is already in use #define SENSOR_ERROR_GPIO_USED 7 // The GPIO is already in use
#define SENSOR_ERROR_CALIBRATION 8 // Calibration error or Not calibrated
#define SENSOR_ERROR_OTHER 99 // Any other error
typedef std::function<void(unsigned char, const char *)> TSensorCallback; typedef std::function<void(unsigned char, const char *)> TSensorCallback;


+ 273
- 0
code/espurna/sensors/CSE7766Sensor.h View File

@ -0,0 +1,273 @@
// -----------------------------------------------------------------------------
// CSE7766 based power monitor
// Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
// http://www.chipsea.com/UploadFiles/2017/08/11144342F01B5662.pdf
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && CSE7766_SUPPORT
#pragma once
#include "Arduino.h"
#include "BaseSensor.h"
#include <SoftwareSerial.h>
class CSE7766Sensor : public BaseSensor {
public:
// ---------------------------------------------------------------------
// Public
// ---------------------------------------------------------------------
CSE7766Sensor(): BaseSensor(), _data() {
_count = 4;
_sensor_id = SENSOR_CSE7766_ID;
}
~CSE7766Sensor() {
if (_serial) delete _serial;
}
// ---------------------------------------------------------------------
void setRX(unsigned char pin_rx) {
if (_pin_rx == pin_rx) return;
_pin_rx = pin_rx;
_dirty = true;
}
void setInverted(bool inverted) {
if (_inverted == inverted) return;
_inverted = inverted;
_dirty = true;
}
// ---------------------------------------------------------------------
unsigned char getRX() {
return _pin_rx;
}
bool getInverted() {
return _inverted;
}
// ---------------------------------------------------------------------
// Sensor API
// ---------------------------------------------------------------------
// Initialization method, must be idempotent
void begin() {
if (!_dirty) return;
if (_serial) delete _serial;
_serial = new SoftwareSerial(_pin_rx, SW_SERIAL_UNUSED_PIN, _inverted, 32);
_serial->enableIntTx(false);
_serial->begin(CSE7766_BAUDRATE);
_ready = true;
_dirty = false;
}
// Descriptive name of the sensor
String description() {
char buffer[28];
snprintf(buffer, sizeof(buffer), "CSE7766 @ SwSerial(%u,NULL)", _pin_rx);
return String(buffer);
}
// Descriptive name of the slot # index
String slot(unsigned char index) {
return description();
};
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
return String(_pin_rx);
}
// Loop-like method, call it in your main loop
void tick() {
_read();
}
// 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;
return MAGNITUDE_NONE;
}
// Current value for slot # index
double value(unsigned char index) {
if (index == 0) return _current;
if (index == 1) return _voltage;
if (index == 2) return _active;
if (index == 3) return _energy;
return 0;
}
protected:
// ---------------------------------------------------------------------
// Protected
// ---------------------------------------------------------------------
/**
* "
* Checksum is the sum of all data
* except for packet header and packet tail lowering by 8bit (...)
* "
* @return bool
*/
bool _checksum() {
unsigned char checksum = 0;
for (unsigned char i = 2; i < 23; i++) {
checksum += _data[i];
}
return checksum == _data[23];
}
void _process() {
// Checksum
if (!_checksum()) {
_error = SENSOR_ERROR_CRC;
#if SENSOR_DEBUG
DEBUG_MSG_P(PSTR("[SENSOR] CSE7766: Checksum error"));
#endif
return;
}
// Calibration
if (0xAA == _data[0]) {
_error = SENSOR_ERROR_CALIBRATION;
#if SENSOR_DEBUG
DEBUG_MSG_P(PSTR("[SENSOR] CSE7766: Chip not calibrated"));
#endif
return;
}
if ((_data[0] & 0xFC) > 0xF0) {
_error = SENSOR_ERROR_OTHER;
#if SENSOR_DEBUG
if (0xF1 == _data[0] & 0xF1) DEBUG_MSG_P(PSTR("[SENSOR] CSE7766: Abnormal coefficient storage area"));
if (0xF2 == _data[0] & 0xF2) DEBUG_MSG_P(PSTR("[SENSOR] CSE7766: Power cycle exceeded range"));
if (0xF4 == _data[0] & 0xF4) DEBUG_MSG_P(PSTR("[SENSOR] CSE7766: Current cycle exceeded range"));
if (0xF8 == _data[0] & 0xF8) DEBUG_MSG_P(PSTR("[SENSOR] CSE7766: Voltage cycle exceeded range"));
#endif
return;
}
// Calibration coefficients
if (0 == _coefV) {
_coefV = (_data[2] << 16 | _data[3] << 8 | _data[4]) / 100;
_coefV *= 100;
_coefC = (_data[8] << 16 | _data[9] << 8 | _data[10]);
_coefP = (_data[14] << 16 | _data[15] << 8 | _data[16]) / 1000;
_coefP *= 1000;
}
// Adj: this looks like a sampling report
uint8_t adj = _data[20];
// Calculate voltage
_voltage = 0;
if ((adj & 0x40) == 0x40) {
unsigned long voltage_cycle = _data[5] << 16 | _data[6] << 8 | _data[7];
_voltage = _coefV / voltage_cycle / CSE7766_V2R;
}
// Calculate power
_active = 0;
if ((adj & 0x10) == 0x10) {
if ((_data[0] & 0xF2) != 0xF2) {
unsigned long power_cycle = _data[17] << 16 | _data[18] << 8 | _data[19];
_active = _coefP / power_cycle / CSE7766_V1R / CSE7766_V2R;
}
}
// Calculate current
_current = 0;
if ((adj & 0x20) == 0x20) {
if (_active > 0) {
unsigned long current_cycle = _data[11] << 16 | _data[12] << 8 | _data[13];
_current = _coefC / current_cycle / CSE7766_V1R;
}
}
// Calculate energy
/*
static unsigned long cf_pulses_last = 0;
unsigned long cf_pulses = _data[21] << 8 | _data[22];
unsigned long frequency = cf_pulses - cf_pulses_last;
cf_pulses_last = cf_pulses;
_energy += (100000 * frequency * _coefP);
*/
}
void _read() {
_error = SENSOR_ERROR_OK;
static unsigned char index = 0;
static unsigned long last = millis();
while (_serial->available()) {
// A 24 bytes message takes ~55ms to go through at 4800 bps
// Reset counter if more than 1000ms have passed since last byte.
if (millis() - last > CSE7766_SYNC_INTERVAL) index = 0;
last = millis();
uint8_t byte = _serial->read();
// second byte in packet must be 0x5A
if ((1 == index) && (0xA5 != byte)) {
index = 0;
} else {
_data[index++] = byte;
if (index > 23) {
_serial->flush();
break;
}
}
}
// Process packet
if (24 == index) {
_process();
index = 0;
}
}
// ---------------------------------------------------------------------
unsigned int _pin_rx = CSE7766_PIN;
bool _inverted = CSE7766_PIN_INVERSE;
SoftwareSerial * _serial = NULL;
double _active = 0;
double _voltage = 0;
double _current = 0;
double _energy = 0;
unsigned long _coefV = 0;
unsigned long _coefC = 0;
unsigned long _coefP = 0;
unsigned char _data[24];
};
#endif // SENSOR_SUPPORT && CSE7766_SUPPORT

+ 2021
- 2020
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 1
- 1
code/html/custom.js View File

@ -62,7 +62,7 @@ function magnitudeType(type) {
function magnitudeError(error) { function magnitudeError(error) {
var errors = [ var errors = [
"OK", "Out of Range", "Warming Up", "Timeout", "Wrong ID", "OK", "Out of Range", "Warming Up", "Timeout", "Wrong ID",
"Data Error", "I2C Error", "GPIO Error"
"Data Error", "I2C Error", "GPIO Error", "Calibration error"
]; ];
if (0 <= error && error < errors.length) { if (0 <= error && error < errors.length) {
return errors[error]; return errors[error];


+ 24
- 0
code/platformio.ini View File

@ -734,6 +734,30 @@ upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200 monitor_baud = 115200
extra_scripts = ${common.extra_scripts} extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-s31]
platform = ${common.platform}
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} -DITEAD_SONOFF_S31
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
[env:itead-sonoff-s31-ota]
platform = ${common.platform}
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} -DITEAD_SONOFF_S31
upload_port = "192.168.4.1"
upload_flags = --auth=fibonacci --port 8266
monitor_baud = 115200
extra_scripts = ${common.extra_scripts}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
[env:electrodragon-wifi-iot] [env:electrodragon-wifi-iot]


Loading…
Cancel
Save