#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CRGB wsled[1]; #define PIN_SEND 2 #define PIN_RECEIVE 3 #define SENSORID 103 #define PIN_LED 7 #define PIN_RELAY 8 #define PIN_SWITCH 6 #define PIN_ENCODER_A 9 #define PIN_ENCODER_B 10 #define PIN_ENCODER_SW 11 const uint8_t encryptKey[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }; Speck cipher; //AES128 cipher; RH_ASK radio(2000, PIN_RECEIVE, PIN_SEND, -1, false); RHEncryptedDriver driver (radio, cipher); LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display CharacterDisplayRenderer renderer(new LiquidCrystal_I2CAdapter(&lcd), 20, 4, 0x7E, 0x7F); LcdMenu menu(renderer); KeyboardAdapter keyboard(&menu, &Serial); TcBUTTON button(PIN_SWITCH); TcBUTTON encbutton(PIN_ENCODER_SW); SimpleRotary encoder(PIN_ENCODER_A, PIN_ENCODER_B, PIN_ENCODER_SW); //#define PZEM_004T PZEM004T pzem(Serial1); uint32_t lastrefreshdisp; uint32_t lasttransmit; char S[10]; struct config_t { uint8_t initok; bool state; bool pstate; uint16_t lcdsleep; bool transmit_enabled; uint16_t transmitinterval; uint16_t tempm; uint16_t tempp; bool wattm_enabled; bool wattp_enabled; uint16_t wattm; uint16_t wattp; uint32_t counter_all; uint32_t counter_used; }; struct mmss_t { uint16_t minute; uint16_t second; }; struct hhmm_t { uint16_t hour; uint16_t minute; }; struct conftemp_t { bool tempm_enabled; bool tempp_enabled; uint32_t tempm; uint32_t tempp; }; struct measure_t { uint16_t count; uint16_t voltage; uint32_t current; uint32_t power; uint32_t energy; uint16_t pf; }; uint8_t rh_payload[17]; struct mmss_t lcdsleep; struct mmss_t transmitinterval; struct hhmm_t tempm; struct hhmm_t tempp; uint32_t counter; struct conftemp_t conftemp; struct measure_t measure_lcd; struct measure_t measure_t433; bool measure_lcd_reset; bool measure_t433_reset; bool measure_kwh_reset; struct config_t config; bool ledblinkstate; bool menu_state; bool lcdsleep_state; uint32_t lastbuttonactivity; void load_config(); void init_config(bool firststart); void save_config(); void reset_time(); void reset_watt(); void reset_all(); void exit_menu(); void PowerOff(); void PowerOn(); void refresh_display(); void refresh_values(); void refresh_counters(); void refresh_confdisplay(); MENU_SCREEN(actionsScreen, actionsItems, ITEM_BOOL_REF("Etat persist", config.pstate, "Oui", "Non", [](const Ref value) { config.pstate = value; save_config(); }, "%s"), ITEM_BOOL_REF("T433", config.transmit_enabled, "Oui", "Non", [](const Ref value) { config.transmit_enabled = value; save_config(); }, "%s"), ITEM_BOOL_REF("Watt-", config.wattm_enabled, "Oui", "Non", [](const Ref value) { config.wattm_enabled = value; save_config(); }, "%s"), ITEM_BOOL_REF("Watt+", config.wattp_enabled, "Oui", "Non", [](const Ref value) { config.wattp_enabled = value; save_config(); }, "%s"), ITEM_BOOL_REF("Tempo avant(-)", conftemp.tempm_enabled, "Oui", "Non", [](const Ref value) { conftemp.tempm_enabled = value; conftemp.tempm = config.tempm*60; if(value) { PowerOff(); } }, "%s"), ITEM_BOOL_REF("Tempo apres(+)", conftemp.tempp_enabled, "Oui", "Non", [](const Ref value) { conftemp.tempp_enabled = value; conftemp.tempp = config.tempp*60; }, "%s")); MENU_SCREEN(settingsScreen, settingsItems, ITEM_RANGE_REF("Watt-", config.wattm, 1, 10, 3670, [](const Ref value) { config.wattm = value; save_config(); }, "%04dW"), ITEM_RANGE_REF("Watt+", config.wattp, 1, 20, 3680, [](const Ref value) { config.wattp = value; save_config(); }, "%04dW"), ITEM_WIDGET( "Ecran(mm:ss)", [](const Ref minute, const Ref second) { config.lcdsleep = minute*60+second; save_config(); }, WIDGET_RANGE_REF(lcdsleep.minute, 1, 0, 59, "%02d", 0, false), WIDGET_RANGE_REF(lcdsleep.second, 1, 0, 59, ":%02d", 0, false)), ITEM_WIDGET( "T433(mm:ss)", [](const Ref minute, const Ref second) { config.transmitinterval = minute*60+second; save_config(); }, WIDGET_RANGE_REF(transmitinterval.minute, 1, 0, 4, "%02d", 0, false), WIDGET_RANGE_REF(transmitinterval.second, 1, 0, 59, ":%02d", 0, false)), ITEM_WIDGET( "Temp-(hh:mm)", [](const Ref hour, const Ref minute) { config.tempm = hour*60+minute; save_config(); }, WIDGET_RANGE_REF(tempm.hour, 1, 0, 23, "%02d", 0, false), WIDGET_RANGE_REF(tempm.minute, 1, 0, 59, ":%02d", 0, false)), ITEM_WIDGET( "Temp+(hh:mm)", [](const Ref hour, const Ref minute) { config.tempp = hour*60+minute; save_config(); }, WIDGET_RANGE_REF(tempp.hour, 1, 0, 23, "%02d", 0, false), WIDGET_RANGE_REF(tempp.minute, 1, 0, 59, ":%02d", 0, false))); MENU_SCREEN(resetScreen, resetItems, ITEM_COMMAND("Reset temps+kWh", []() { reset_all(); }), ITEM_COMMAND("Reset temps", []() { reset_time(); }), ITEM_COMMAND("Reset kWh", []() { reset_watt(); }), ITEM_COMMAND("Reset conf. usine", []() { init_config(false); }) ); MENU_SCREEN(mainScreen, mainItems, ITEM_SUBMENU("Actions", actionsScreen), ITEM_SUBMENU("Reglages", settingsScreen), ITEM_SUBMENU("Reset", resetScreen), ITEM_COMMAND("Sortir du menu", []() { exit_menu(); })); void exit_menu() { lastbuttonactivity=millis(); menu_state=false; save_config(); menu.hide(); refresh_display(); refresh_counters(); refresh_confdisplay(); } void save_config() { EEPROM.put(0, config); EEPROM.commit(); } void init_config(bool firststart) { config.initok = 42; config.state = false; config.pstate = false; config.lcdsleep = 60; config.transmit_enabled = true; config.transmitinterval = 15; config.wattm_enabled = false; config.wattp_enabled = false; config.wattm = 100; config.wattp = 2000; config.tempm = 60; config.tempp = 720; if(firststart) { config.counter_all = 0; config.counter_used = 0; } save_config(); load_config(); } void load_config() { EEPROM.get(0, config); lcdsleep.minute = config.lcdsleep / 60; lcdsleep.second = config.lcdsleep % 60; transmitinterval.minute = config.transmitinterval / 60; transmitinterval.second = config.transmitinterval % 60; tempm.hour = config.tempm / 60; tempm.minute = config.tempm % 60; tempp.hour = config.tempp / 60; tempp.minute = config.tempp % 60; } void reset_time() { config.counter_all=0; config.counter_used=0; } void reset_watt() { measure_kwh_reset = true; } void reset_all() { reset_time(); reset_watt(); } void clear_lcd_temp() { if(menu_state == false) { lcd.setCursor(3, 3); lcd.print(" "); } } void PowerOn() { config.state=true; conftemp.tempm_enabled = false; clear_lcd_temp(); refresh_confdisplay(); save_config(); digitalWrite(PIN_LED, HIGH); digitalWrite(PIN_RELAY, HIGH); } void PowerOff() { config.state=false; conftemp.tempp_enabled = false; clear_lcd_temp(); refresh_confdisplay(); measure_lcd_reset = true; measure_t433_reset = true; save_config(); digitalWrite(PIN_LED, LOW); digitalWrite(PIN_RELAY, LOW); } char* create_value(uint32_t value, char *ret, String unit, uint8_t factor, uint8_t factor2, uint8_t maxchar) { char valuestr[10]; ret[0]='\0'; dtostrf(value/pow(10,factor2), maxchar, factor, valuestr); if(strlen(valuestr) < maxchar) { for(int i=0;i 0) { conftemp.tempm--; } else { conftemp.tempm = config.tempm*60; PowerOn(); } } if(conftemp.tempp_enabled == true && config.state == true) { if(conftemp.tempp > 0) { conftemp.tempp--; } else { conftemp.tempp = config.tempp*60; PowerOff(); } } if(menu_state == false) { refresh_values(); refresh_temp(); if(config.state) { refresh_counters(); } } } char confdisplay_char(char c, bool b) { return b?c:'-'; } void refresh_confdisplay() { if(menu_state == false) { char confdisplay[5]; sprintf(confdisplay, "%c%c%c%c%c", confdisplay_char('w', config.wattm_enabled), confdisplay_char('W', config.wattp_enabled), confdisplay_char('t', conftemp.tempm_enabled), confdisplay_char('T', conftemp.tempp_enabled), confdisplay_char('X', config.transmit_enabled)); lcd.setCursor(15, 3); lcd.print(confdisplay); } } void blink() { wsled[0] = CRGB::Red; FastLED.show(); delay(100); wsled[0] = CRGB::Black; FastLED.show(); } void setSensorType(uint8_t stype) { uint8_t payload0; payload0 = stype << 4; rh_payload[0] &= 0b00001111; rh_payload[0] += payload0; } void printHex(uint8_t num) { char hexCar[2]; sprintf(hexCar, "%02X", num); Serial.print(hexCar); } void transmit() { Serial.println("Transmit"); //blink(); if(config.state == true) { rh_payload[0] |= 0b00000001; } else { rh_payload[0] &= 0b11111110; } rh_payload[1] = measure_t433.voltage >> 8; rh_payload[2] = measure_t433.voltage; rh_payload[3] = measure_t433.current >> 24; rh_payload[4] = measure_t433.current >> 16; rh_payload[5] = measure_t433.current >> 8; rh_payload[6] = measure_t433.current; rh_payload[7] = measure_t433.power >> 24; rh_payload[8] = measure_t433.power >> 16; rh_payload[9] = measure_t433.power >> 8; rh_payload[10] = measure_t433.power; rh_payload[11] = measure_t433.energy >> 24; rh_payload[12] = measure_t433.energy >> 16; rh_payload[13] = measure_t433.energy >> 8; rh_payload[14] = measure_t433.energy; rh_payload[15] = measure_t433.pf >> 8; rh_payload[16] = measure_t433.pf; measure_t433_reset = true; Serial.print("Hex RH Payload: "); for(int i=0;i<17;i++) { printHex(rh_payload[i]); } Serial.println(); driver.send(rh_payload, 17); driver.waitPacketSent(); } void onHoldButton() { Serial.println("Button Held for 2 seconds!"); if(lcdsleep_state == false) { lastbuttonactivity=millis(); } else { reset_all(); } } void onPressButton() { lastbuttonactivity=millis(); if(lcdsleep_state) { lcd.backlight(); lcd.display(); } else { //Power } } void onPressEncButton() { lastbuttonactivity=millis(); if(lcdsleep_state) { lcd.backlight(); lcd.display(); } else { menu_state = true; menu.show(); } } void setup() { pinMode(PIN_LED, OUTPUT_12MA); digitalWrite(PIN_LED, LOW); pinMode(PIN_RELAY, OUTPUT_12MA); digitalWrite(PIN_RELAY, LOW); Serial.begin(); FastLED.addLeds(wsled, 1); EEPROM.begin(256); delay(500); if (!driver.init()) { Serial.println("RH init failed"); } driver.setHeaderId(SENSORID); cipher.setKey(encryptKey, sizeof(encryptKey)); setSensorType(3); load_config(); conftemp.tempm_enabled = false; conftemp.tempp_enabled = false; conftemp.tempm = config.tempm*60; conftemp.tempp = config.tempp*60; measure_lcd.count=0; measure_lcd.voltage=2305; measure_lcd.current=1023; measure_lcd.power=14567; measure_lcd.energy=19876; measure_lcd.pf=5; measure_t433.count=0; measure_t433.voltage=2305; measure_t433.current=1023; measure_t433.power=14567; measure_t433.energy=19876; measure_t433.pf=5; if(config.initok != 42) { init_config(true); } //init_config(true); lcd.init(); // initialize the lcd button.setOnHold(onHoldButton, 2000); button.setOnPress(onPressButton); encbutton.setOnPress(onPressEncButton); config.state=true; renderer.begin(); menu.setScreen(mainScreen); menu_state = true; //menu.hide(); //init_config(); //save_config(); load_config(); if(config.pstate == true && config.state == true) { PowerOn(); } else if(config.pstate == false) { config.state=false; save_config(); } refresh_confdisplay(); lastrefreshdisp = millis(); if(menu_state == false) { refresh_display(); refresh_counters(); } lcd.backlight(); transmit(); } void setup1() { pzem.begin(); } bool timer_ok(uint32_t lastmillis, uint16_t seconds) { if(millis() < lastmillis) { return UINT16_MAX-lastmillis+millis() > seconds*1000; Serial.println("millis reset"); } else { return millis() > lastmillis+seconds*1000; } } void loop() { if(timer_ok(lastrefreshdisp, 1)) { lastrefreshdisp = millis(); //blink(); refresh_display(); } if(conftemp.tempm_enabled) { if(millis() % 1000 > 500) { if(ledblinkstate == false) { ledblinkstate = true; wsled[0] = CRGB::Red; FastLED.show(); } //Serial.println("On"); } else { if(ledblinkstate) { ledblinkstate = false; wsled[0] = CRGB::Black; FastLED.show(); } //Serial.println("Off"); } } if(menu_state == true) { menu.poll(1000); keyboard.observe(); } else { button.update(); encbutton.update(); if(lcdsleep_state == false && timer_ok(lastbuttonactivity, config.lcdsleep)) { lcdsleep_state = true; lcd.noBacklight(); lcd.noDisplay(); } } if(((config.transmit_enabled == false || config.state == false) && timer_ok(lasttransmit, 30)) || (config.state == true && config.transmit_enabled == true && timer_ok(lasttransmit, config.transmitinterval))) { lasttransmit = millis(); transmit(); } } void add_value_measure_16(uint16_t value, uint16_t count, uint16_t *average) { *average = *average + ((value + *average) / count); } void add_value_measure_32(uint32_t value, uint16_t count, uint32_t *average) { *average = *average + ((value + *average) / count); } void loop1() { /* uint16_t voltage, frequency, powerFactor; uint32_t current, power, energy; if(measure_kwh_reset == true) { pzem.resetEnergy(); measure_kwh_reset = false; } if(pzem.readAllRaw(&voltage, ¤t, &power, &energy, &frequency, &powerFactor)) { if(measure_t433_reset == true) { measure_t433.count = 0; measure_t433.voltage = 0; measure_t433.current = 0; measure_t433.power = 0; measure_t433.energy = 0; measure_t433.pf = 0; measure_t433_reset = false; } if(measure_lcd_reset == true) { measure_lcd.count = 0; measure_lcd.voltage = 0; measure_lcd.current = 0; measure_lcd.power = 0; measure_lcd.energy = 0; measure_lcd.pf = 0; measure_lcd_reset = false; } measure_t433.count++; add_value_measure_16(voltage, measure_t433.count, &(measure_t433.voltage)); add_value_measure_32(current, measure_t433.count, &(measure_t433.current)); add_value_measure_32(power, measure_t433.count, &(measure_t433.power)); measure_t433.energy = energy; add_value_measure_16(powerFactor, measure_t433.count, &(measure_t433.pf)); measure_lcd.count++; add_value_measure_16(voltage, measure_lcd.count, &(measure_lcd.voltage)); add_value_measure_32(current, measure_lcd.count, &(measure_lcd.current)); add_value_measure_32(power, measure_lcd.count, &(measure_lcd.power)); measure_lcd.energy = energy; add_value_measure_16(powerFactor, measure_lcd.count, &(measure_lcd.pf)); } */ delay(1000); }