Sonoff Pow R2 Arduino

elmaya
Posty: 1125
Rejestracja: śr cze 27, 2018 5:48 pm
Lokalizacja: Sevilla

czw gru 17, 2020 6:37 pm

Screenshot_20201217-144240.png
Screenshot_20201217-144240.png (51.6 KiB) Przejrzano 497 razy

To access the Wi-Fi configuration, press button for at least 5 seconds, Led winks in wificonfig.
in the configuration page enter the data for "suplaServer, Email and Supla Device Name (name with which it will be seen in the cloud and DHCP)"
Captura de pantalla (96).png
Captura de pantalla (96).png (23.51 KiB) Przejrzano 497 razy
expectedVoltage - for calibration.
expectedActivePower - for calibration.
clear counter - reset pulse counter.

calibration process:
connect a resistive load with a known consumption, for example a 60W bulb.
access wificonfig (button pressed 5 seconds)
in the "expectedVoltage" field set the voltage of your line for example 227.
in the "expectedActivePower" field, set the consumption of the connected load, for example 60.
press save.
The procedure takes about 15 seconds, then the device restarts and the readings will be correct.
the calibration is only executed if there are data in both fields "expectedVoltage" and "expectedActivePower"
This allows for example to change the Wi-Fi network without recalibrating.

Kod: Zaznacz cały

/*
Copyright (C) AC SOFTWARE SP. Z O.O.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#define supla_lib_config_h_  // silences unnecessary debug messages "should be disabled by default"
#include "LittleFS.h"
#include <SuplaDevice.h>
#include <supla/sensor/one_phase_electricity_meter.h>
#include <supla/io.h>
#include <supla/control/relay.h>
#include <WiFiManager.h>
#include <ArduinoJson.h> //--------- V6 ------
#include <EEPROM.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <Ticker.h>      //for LED status
#include <ESP8266TrueRandom.h>
#include "CSE7766.h"
extern "C"
{
#include "user_interface.h"
} 

/*
GPIO00  Button1
GPIO01  CSE7766 Tx
GPIO03  CSE7766 Rx
GPIO12  Relay1
GPIO13  Led1i
 */

#define CSE7766_RX_PIN 3
#define status_led 13     
#define wificonfig_pin 0
#define relay_pin  12       
int C_W_state = HIGH; 
int last_C_W_state = HIGH;
unsigned long time_last_C_W_change = 0; 
long C_W_delay = 5000;                      // config delay 5 seconds  new
int C_W_state2 = HIGH; 
long C_W_delay2 = 100;
unsigned long eep_milis = 10000;
bool recover = true;                       
char Supla_server[81]=("Set server address");
char Email[81]=("set email address");
char Supla_name[51];
char Supla_status[51];
char Volt[8];
char Wats[8];
byte mac[6];
bool shouldSaveConfig = false;
bool initialConfig = false;
int s = 0;
bool starting = true;
bool Tik = true;
unsigned long  mem_energy_milis = 300000;
float mem_energy = 0;
float _mem_energy = 0;
int customFieldLength = 40;
WiFiManagerParameter custom_field; 
char GUID[SUPLA_GUID_SIZE];
char AUTHKEY[SUPLA_AUTHKEY_SIZE];
byte uuidNumber[16]; 
static const char custom_radio_str[] PROGMEM = "<br><div style='text-align:center; width:100%; padding:0;'><label for='customfieldid'>Counter mem</label><input type='radio' name='customfieldid' value='0' checked>keep Storage<input type='radio' name='customfieldid' value='1'>clear Storage</div>";
ESP8266WebServer httpServer(81);
ESP8266HTTPUpdateServer httpUpdater;
WiFiManager wifiManager;
Ticker ticker;
#include <supla/network/esp_wifi.h>
Supla::ESPWifi wifi("", "");  //------ Do not edit----wifimanager takes care------

Supla::Control::Relay *relay1 = nullptr;

#define CSE7766_CURRENT_RATIO             16030
#define CSE7766_VOLTAGE_RATIO             190770
#define CSE7766_POWER_RATIO               5195000
CSE7766 myCSE7766;

class MyCSE7766 : public Supla::Sensor::OnePhaseElectricityMeter {
    public:
        MyCSE7766()  {
        }
        void onInit() {
            readValuesFromDevice();
            updateChannelValues();
        }

        virtual void readValuesFromDevice() {
          myCSE7766.handle();                                   
            // voltage in 0.01 V
            setVoltage(0,myCSE7766.getVoltage() * 100);
            // current in 0.001 A
            setCurrent(0, myCSE7766.getCurrent() * 1000);
            // power in 0.00001 kW
            setPowerActive(0, myCSE7766.getActivePower() * 100000);
            // energy in 0.00001 kWh
            setFwdActEnergy(0, ((float)myCSE7766.getEnergy() + mem_energy) / 6 / 6 );
            // power in 0.00001 kVA 
            setPowerApparent(0, myCSE7766.getApparentPower() * 100000);
            // power in 0.00001 kvar 
            setPowerReactive(0, myCSE7766.getReactivePower() * 100000);
            // power in 0.001
            setPowerFactor(0, myCSE7766.getPowerFactor() * 1000);
            //float powerFactor = 0; setPowerFactor(0, powerFactor * 1000);
        }
};

void tick() {
  int state = digitalRead(status_led);  
  digitalWrite(status_led, !state);     
}
void calibrate_CSE7766() {
   int ex_volt = atoi(Volt); 
   int ex_pow = atoi(Wats);
   double ex_amps = ((float)ex_pow / (float)ex_volt);

   digitalWrite(relay_pin,HIGH);   
    myCSE7766.handle(); 
    unsigned long timeout1 = millis();
    while ((millis() - timeout1) < 10000) { delay(10);}  
    myCSE7766.handle();           
    myCSE7766.expectedPower(ex_pow);
    myCSE7766.expectedVoltage(ex_volt);
    myCSE7766.expectedCurrent(ex_amps);   
    unsigned long timeout2 = millis();
    while ((millis() - timeout2) < 2000) {delay(10);}          
    double current_multi = myCSE7766.getCurrentRatio();
    double voltage_multi = myCSE7766.getVoltageRatio();
    double power_multi = myCSE7766.getPowerRatio();
    EEPROM.put(400, current_multi);
    EEPROM.put(410, voltage_multi);
    EEPROM.put(420, power_multi);
    EEPROM.write(430, 60);
    EEPROM.commit();
  yield();
    
}
void get_CSE7766_config(){
  if (EEPROM.read(430) == 60){
       double p_m;double v_m;double c_m;
        EEPROM.get(400,c_m);
         EEPROM.get(410,v_m);
          EEPROM.get(420,p_m);
           myCSE7766.setCurrentRatio(c_m);
            myCSE7766.setVoltageRatio(v_m);
             myCSE7766.setPowerRatio(p_m);
   }
}
void saveConfigCallback () {          
  Serial.println("Should save config");
  shouldSaveConfig = true;
}
void ondemandwifiCallback () {
   ticker.attach(0.15, tick); // new (old 1.5)

   WiFiManagerParameter custom_Supla_server("server", "supla server", Supla_server, 81,"required");
   WiFiManagerParameter custom_Email("email", "Email", Email, 81,"required");
   WiFiManagerParameter custom_Supla_name("name", "Supla Device Name", Supla_name, 51,"required");
   WiFiManagerParameter custom_html_id21("<div><h4> - Supla State -   ");
   WiFiManagerParameter custom_html_id22( Supla_status);
   WiFiManagerParameter custom_html_id23( "</h4></div>");
   WiFiManagerParameter custom_Volt("Volt", "expectedVoltage", Volt, 8);
   WiFiManagerParameter custom_Wats("Wats", "expectedActivePower", Wats, 8);
   
   new (&custom_field) WiFiManagerParameter(custom_radio_str); // custom html input

   wifiManager.setBreakAfterConfig(true);
   wifiManager.setSaveConfigCallback(saveConfigCallback);
   wifiManager.setSaveParamsCallback(saveParamCallback);
  
   wifiManager.addParameter(&custom_Supla_server);
   wifiManager.addParameter(&custom_Email);
   wifiManager.addParameter(&custom_Supla_name);
   wifiManager.addParameter(&custom_html_id21);
   wifiManager.addParameter(&custom_html_id22);
   wifiManager.addParameter(&custom_html_id23);
   wifiManager.addParameter(&custom_Volt);
   wifiManager.addParameter(&custom_Wats);
   wifiManager.addParameter(&custom_field);

   wifiManager.setCustomHeadElement("<style>html{ background-color: #01DF3A;}</style><div class='s'><svg version='1.1' id='l' x='0' y='0' viewBox='0 0 200 200' xml:space='preserve'><path d='M59.3,2.5c18.1,0.6,31.8,8,40.2,23.5c3.1,5.7,4.3,11.9,4.1,18.3c-0.1,3.6-0.7,7.1-1.9,10.6c-0.2,0.7-0.1,1.1,0.6,1.5c12.8,7.7,25.5,15.4,38.3,23c2.9,1.7,5.8,3.4,8.7,5.3c1,0.6,1.6,0.6,2.5-0.1c4.5-3.6,9.8-5.3,15.7-5.4c12.5-0.1,22.9,7.9,25.2,19c1.9,9.2-2.9,19.2-11.8,23.9c-8.4,4.5-16.9,4.5-25.5,0.2c-0.7-0.3-1-0.2-1.5,0.3c-4.8,4.9-9.7,9.8-14.5,14.6c-5.3,5.3-10.6,10.7-15.9,16c-1.8,1.8-3.6,3.7-5.4,5.4c-0.7,0.6-0.6,1,0,1.6c3.6,3.4,5.8,7.5,6.2,12.2c0.7,7.7-2.2,14-8.8,18.5c-12.3,8.6-30.3,3.5-35-10.4c-2.8-8.4,0.6-17.7,8.6-22.8c0.9-0.6,1.1-1,0.8-2c-2-6.2-4.4-12.4-6.6-18.6c-6.3-17.6-12.7-35.1-19-52.7c-0.2-0.7-0.5-1-1.4-0.9c-12.5,0.7-23.6-2.6-33-10.4c-8-6.6-12.9-15-14.2-25c-1.5-11.5,1.7-21.9,9.6-30.7C32.5,8.9,42.2,4.2,53.7,2.7c0.7-0.1,1.5-0.2,2.2-0.2C57,2.4,58.2,2.5,59.3,2.5z M76.5,81c0,0.1,0.1,0.3,0.1,0.6c1.6,6.3,3.2,12.6,4.7,18.9c4.5,17.7,8.9,35.5,13.3,53.2c0.2,0.9,0.6,1.1,1.6,0.9c5.4-1.2,10.7-0.8,15.7,1.6c0.8,0.4,1.2,0.3,1.7-0.4c11.2-12.9,22.5-25.7,33.4-38.7c0.5-0.6,0.4-1,0-1.6c-5.6-7.9-6.1-16.1-1.3-24.5c0.5-0.8,0.3-1.1-0.5-1.6c-9.1-4.7-18.1-9.3-27.2-14c-6.8-3.5-13.5-7-20.3-10.5c-0.7-0.4-1.1-0.3-1.6,0.4c-1.3,1.8-2.7,3.5-4.3,5.1c-4.2,4.2-9.1,7.4-14.7,9.7C76.9,80.3,76.4,80.3,76.5,81z M89,42.6c0.1-2.5-0.4-5.4-1.5-8.1C83,23.1,74.2,16.9,61.7,15.8c-10-0.9-18.6,2.4-25.3,9.7c-8.4,9-9.3,22.4-2.2,32.4c6.8,9.6,19.1,14.2,31.4,11.9C79.2,67.1,89,55.9,89,42.6z M102.1,188.6c0.6,0.1,1.5-0.1,2.4-0.2c9.5-1.4,15.3-10.9,11.6-19.2c-2.6-5.9-9.4-9.6-16.8-8.6c-8.3,1.2-14.1,8.9-12.4,16.6C88.2,183.9,94.4,188.6,102.1,188.6z M167.7,88.5c-1,0-2.1,0.1-3.1,0.3c-9,1.7-14.2,10.6-10.8,18.6c2.9,6.8,11.4,10.3,19,7.8c7.1-2.3,11.1-9.1,9.6-15.9C180.9,93,174.8,88.5,167.7,88.5z'/></svg>");
   wifiManager.setMinimumSignalQuality(8);
   //wifiManager.setShowStaticFields(true); // force show static ip fields
   //wifiManager.setShowDnsFields(true);    // force show dns field always
   wifiManager.setConfigPortalTimeout(180);

   if (!wifiManager.startConfigPortal("Sonoff_POW_R2")) { Serial.println("Not connected to WiFi but continuing anyway.");} else { Serial.println("connected...yeey :)");}                
    strcpy(Supla_server, custom_Supla_server.getValue());
    strcpy(Email, custom_Email.getValue());
    strcpy(Supla_name, custom_Supla_name.getValue()); 
    strcpy(Volt, custom_Volt.getValue());
    strcpy(Wats, custom_Wats.getValue());
    if(strcmp(Supla_server, "get_new_guid_and_authkey") == 0){
      Serial.println("new guid & authkey.");
      EEPROM.write(300, 0);
      EEPROM.commit();
      ESP.reset(); 
    }
    if ((strlen(Volt) != 0) && (strlen(Wats) != 0)){
      calibrate_CSE7766();
    }
    WiFi.softAPdisconnect(true);   //  close AP

}
void status_func(int status, const char *msg) {    //    ------------------------ Status --------------------------
  if (s != status){
    s = status; 
      if (s != 10){
        strcpy(Supla_status, msg);
  }  }            
}
String getParam(String name){
  String value;
  if(wifiManager.server->hasArg(name)) {
    value = wifiManager.server->arg(name);
      if (value == "1"){
        float cler = 0.0; 
         EEPROM.put(460, cler);
          EEPROM.commit();
         }
  }
  return value;
}
void saveParamCallback(){
 // Serial.println("[CALLBACK] saveParamCallback fired");
 // Serial.println("PARAM customfieldid = " + getParam("customfieldid"));
}

void Eeprom_save(){
  if (digitalRead(relay_pin)!= EEPROM.read(431)){
    _mem_energy = (double)myCSE7766.getEnergy() + mem_energy;
    EEPROM.put(460, _mem_energy);
    EEPROM.write(431,digitalRead(relay_pin));
    EEPROM.commit();
  }
}
void guid_authkey(void) {
  if (EEPROM.read(300) != 60){
    int eep_gui = 301;

    ESP8266TrueRandom.uuid(uuidNumber);

    String uuidString = "";
    for (int i = 0; i < 16; i++) {
      int topDigit = uuidNumber[i] >> 4;
      int bottomDigit = uuidNumber[i] & 0x0f;
      uuidString += "0123456789abcdef"[topDigit];
      uuidString += "0123456789abcdef"[bottomDigit];
    }
    int length_uuid = uuidString.length();
    for (int i = 0; i < length_uuid; ++i) {
      EEPROM.put(eep_gui + i, uuidString[i]);
    }

    int eep_aut = 341;

    ESP8266TrueRandom.uuid(uuidNumber);

    String uuidString2 = "";
    for (int i = 0; i < 16; i++) {
      int topDigit = uuidNumber[i] >> 4;
      int bottomDigit = uuidNumber[i] & 0x0f;
      uuidString2 += "0123456789abcdef"[topDigit];
      uuidString2 += "0123456789abcdef"[bottomDigit];
    }
    int length_uuid2 = uuidString2.length();
    for (int i = 0; i < length_uuid2; ++i) {
      EEPROM.put(eep_aut + i, uuidString2[i]);
    }
    float cler = 0.0;
    EEPROM.put(460, cler);
    EEPROM.write(300, 60);
    EEPROM.commit();
  }
  read_guid();
  read_authkey();
}

String read_guid(void) {
  String read_eeprom = "";
  int i, ii = 0;
  int eep_star = 301;
  int end_guid = eep_star + SUPLA_GUID_SIZE;
  String temp_read = "0x";
  for (i = eep_star; i < end_guid + 16;  i = i + 1) {
    temp_read += char(EEPROM.read(i));
    read_eeprom += char(EEPROM.read(i));
    if ( (i % 2) == 0) {
      char *_guid = strcpy((char*)malloc(temp_read.length() + 1), temp_read.c_str());
      GUID[ii] = strtoul( _guid, NULL, 16);
      temp_read = "0x";
      ii++;
    }
  }
  return read_eeprom;
}
String read_authkey(void) {
  String read_eeprom = "";
  int i, ii = 0;
  int eep_star = 341;
  int end_authkey = eep_star + SUPLA_AUTHKEY_SIZE;
  String temp_read = "0x";
  for (i = eep_star; i < end_authkey + 16;  i = i + 1) {
    temp_read += char(EEPROM.read(i));
    read_eeprom += char(EEPROM.read(i));
    if ( (i % 2) == 0) {
      char *_authkey = strcpy((char*)malloc(temp_read.length() + 1), temp_read.c_str());
      AUTHKEY[ii] = strtoul( _authkey, NULL, 16);
      temp_read = "0x";
      ii++;
    }
  }
  return read_eeprom;
}
void setup() {
  wifi_set_sleep_type(NONE_SLEEP_T);
  Serial.begin(4800);
  Serial.println();
  EEPROM.begin(1024);
  pinMode(wificonfig_pin, INPUT_PULLUP); 
  pinMode(status_led,OUTPUT);
  digitalWrite(relay_pin, EEPROM.read(431));  
  guid_authkey();
  ticker.attach(0.8, tick); 
  
  if (WiFi.SSID()==""){ initialConfig = true;} 

  if (LittleFS.begin()) {  // ------------------------- wificonfig read -----------------
    Serial.println("mounted file system");
    if (LittleFS.exists("/config.json")) {
      Serial.println("reading config file");
       File configFile = LittleFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
         size_t size = configFile.size();
         std::unique_ptr<char[]> buf(new char[size]);
         configFile.readBytes(buf.get(), size);
        DynamicJsonDocument json(1024);
        DeserializationError deserializeError = deserializeJson(json, buf.get());
        serializeJsonPretty(json, Serial);
        if (!deserializeError) {Serial.println("\nparsed json");         
          if (json.containsKey("Supla_server")) strcpy(Supla_server, json["Supla_server"]);
          if (json.containsKey("Email")) strcpy(Email, json["Email"]);
          if (json.containsKey("Supla_name")) strcpy(Supla_name, json["Supla_name"]);       
        } else {
          Serial.println("failed to load json config");
           initialConfig = true;
        }
        configFile.close(); 
      }
    }
   } else {
    Serial.println("failed to mount FS");
  } 
   wifi_station_set_hostname(Supla_name);
  
     myCSE7766.setCurrentRatio(CSE7766_CURRENT_RATIO);
     myCSE7766.setVoltageRatio(CSE7766_VOLTAGE_RATIO);
     myCSE7766.setPowerRatio(CSE7766_POWER_RATIO);
     myCSE7766.setRX(CSE7766_RX_PIN);
     myCSE7766.begin(); // will initialize serial to 4800 bps
     get_CSE7766_config();
     
    EEPROM.get(460, mem_energy);
    _mem_energy = mem_energy;

    relay1 = new Supla::Control::Relay(relay_pin);
    new MyCSE7766(); 
            
    SuplaDevice.setName(Supla_name);
    SuplaDevice.setStatusFuncImpl(&status_func);
    wifi.enableSSL(false);  
    SuplaDevice.begin(GUID,Supla_server,Email,AUTHKEY);
                      
}
char buffer[50];
void loop() {
  
  if (initialConfig == true){ondemandwifiCallback();EEPROM.write(431, 0); EEPROM.commit();}

   int C_W_read = digitalRead(wificonfig_pin);{  
   if (C_W_read != last_C_W_state) {            
     time_last_C_W_change = millis();
   }
   if ((millis() - time_last_C_W_change) > C_W_delay2) {     
     if (C_W_read != C_W_state2) {     
       C_W_state2 = C_W_read; 
       if (C_W_state2 == LOW) {     
         if (!relay1->isOn()) {
          relay1->turnOn();
          yield();
          Eeprom_save() ;
       }else{
         relay1->turnOff();
         yield();
         Eeprom_save() ;
     }}}       
    }
   if ((millis() - time_last_C_W_change) > C_W_delay) {     
     if (C_W_read != C_W_state) {     
       C_W_state = C_W_read;       
       if (C_W_state == LOW) {
        ondemandwifiCallback () ;
       }
     }
    }
   last_C_W_state = C_W_read;            
 }
  
  if (shouldSaveConfig == true) { // ------------------------ wificonfig save --------------
    Serial.println(" config...");  
    DynamicJsonDocument json(1024);
    json["Supla_server"] = Supla_server;
    json["Email"] = Email;
    json["Supla_name"] = Supla_name;
    File configFile = LittleFS.open("/config.json", "w");
    if (!configFile) {Serial.println("failed to open config file for writing");}    
    serializeJson(json, configFile);
    serializeJsonPretty(json, Serial);
    delay(5000);
    configFile.close();
    Serial.println("Config written successfully");
    shouldSaveConfig = false;
    initialConfig = false; 
    WiFi.mode(WIFI_STA);   
    delay(5000);
    ESP.restart();     
  }
  
  if (s == 17){
    if ((Tik == true) && (WiFi.status() == WL_CONNECTED)){ticker.detach();digitalWrite(status_led, LOW);Tik = false;}
    if(millis() > eep_milis){
     Eeprom_save() ;
     eep_milis = millis() + 3000 ; 
    }
    if (recover){
      if (EEPROM.read(431) == true){
       relay1->turnOn();
        yield();
          eep_milis = millis() + 3000 ;
       }
       recover = false; 
      }
    }
  if (((s != 17) || (WiFi.status() != WL_CONNECTED)) && (Tik == false)) { ticker.attach(0.8, tick);Tik = true; }           
  if (s == 10){recover = true;} 
     
   SuplaDevice.iterate();
   delay(25);
   
   if (WiFi.status() == WL_CONNECTED){
    if (starting){
      httpUpdater.setup(&httpServer, "/update", "admin", "pass"); // -- set here path, username and password for OTA. --
      httpServer.begin(); 
      starting = false;         
     }
    httpServer.handleClient();
   }

   if(millis() > mem_energy_milis){
    if ((float(myCSE7766.getEnergy()) + mem_energy > _mem_energy) && (digitalRead(relay_pin) == HIGH)){
      _mem_energy = (float)myCSE7766.getEnergy() + mem_energy;
      EEPROM.put(460, _mem_energy);
      EEPROM.commit();
     mem_energy_milis = millis() + 600000 ;  
    }
   }
}
POW2_DOUT_8Mbit.rar
Compiled firmware
(380.6 KiB) Pobrany 17 razy
Sonoff_pow_2.rar
imo & libraries
(13.3 KiB) Pobrany 18 razy
PioKar
Posty: 398
Rejestracja: czw maja 03, 2018 5:56 am

pn sty 25, 2021 10:44 am

Cześć @elmaya.
Działa super.
Koledzy pytają czy dało by się dodać DS18b20 pod io4 lub io3.
Jeśli to nie problem to poproszę .bin
Pozdrawiam.
Piotr.
Załączniki
pow.jpg
pow.jpg (68.06 KiB) Przejrzano 50 razy
elmaya
Posty: 1125
Rejestracja: śr cze 27, 2018 5:48 pm
Lokalizacja: Sevilla

pn sty 25, 2021 10:54 am

I will not add DS18B20 for your own safety.
This device does not have galvanic isolation, the DS18B20 would be connected to the "240vAC" electrical network.
it would be too dangerous!
PioKar
Posty: 398
Rejestracja: czw maja 03, 2018 5:56 am

pn sty 25, 2021 12:33 pm

ok.
I tak dziękuję.
ODPOWIEDZ

Wróć do „Sonoff POW”