In general, of course, it would be better to start with a “mockup”, but in this case it turned out that the prototype was made later than the resulting device.
When forming the list of functions - actively communicate with the home. For example, it was reasonable for me to suggest that the time after which the automatic activation of ventilation should take place is too short and there will be unnecessary alarms and, in general, all the time parameters should be able to be adjusted during operation.
typedef struct { int button; // int relay; // boolean state; // (/) unsigned long power_on; // , unsigned long auto_off; // , unsigned long time_off; // , boolean autostate; // , , unsigned long press_start; // , unsigned long press_stop; // , } Channel;
// #include <avr/wdt.h> #include <Bounce.h> //#define DEBUG // - // #define CH 2 // #define LONGPRESS 2000 // 2 // "" typedef struct { int button; // int relay; // boolean state; // (/) unsigned long power_on; // , unsigned long auto_off; // , unsigned long time_off; // , boolean autostate; // , , unsigned long press_start; // , unsigned long press_stop; // , } Channel; // Channel MySwitch[CH] = { 15, 3, LOW, 0, 3600000, 0, false, 0, 0, 14, 4, LOW, 0, 600000, 0, false, 0, 0 }; // Bounce. , . Bounce bouncer0 = Bounce(MySwitch[0].button,5); Bounce bouncer1 = Bounce(MySwitch[1].button,5); // boolean logicFlag = false; boolean onFlag = false; boolean offFlag = false; void setup() { wdt_disable(); // bootloop #ifndef DEBUG Serial.begin(9600); Serial.println("Start!"); pinMode(13, OUTPUT); #endif // pinMode(MySwitch[0].relay, OUTPUT); pinMode(MySwitch[1].relay, OUTPUT); // pinMode(MySwitch[0].button, INPUT); pinMode(MySwitch[1].button, INPUT); // digitalWrite(MySwitch[0].button, HIGH); digitalWrite(MySwitch[1].button, HIGH); //delay(5000); // , bootloop #ifndef DEBUG Serial.println("Ready!"); #endif wdt_enable (WDTO_8S); // 8 . } void loop() { // button_read(); // autoOff(); // chkLogic(); // wdt_reset(); } void button_read(){ // 1 if ( bouncer0.update() ) { if ( bouncer0.read() == LOW) { // MySwitch[0].press_start = millis(); } else { // , ( ) , . pressDetect(0, millis()); } } // 2 if ( bouncer1.update() ) { if ( bouncer1.read() == LOW) { MySwitch[1].press_start = millis(); } else { pressDetect(1, millis()); } } } // void doSwitch(int ch, boolean state){ // MySwitch[ch].state = state; // "" if (MySwitch[ch].state == HIGH) { // MySwitch[ch].power_on = millis(); if(MySwitch[ch].auto_off > 0) { // , MySwitch[ch].time_off = MySwitch[ch].power_on + MySwitch[ch].auto_off; MySwitch[ch].autostate = true; } #ifndef DEBUG Serial.print("ON "); Serial.println(ch); #endif } else { // MySwitch[ch].autostate = false; // MySwitch[ch].time_off = 0; #ifndef DEBUG Serial.print("OFF "); Serial.println(ch); #endif } digitalWrite(MySwitch[ch].relay,MySwitch[ch].state); } // void autoOff(){ // for (int i=0; i < CH; i++) { // - if ((millis() >= MySwitch[i].time_off) && MySwitch[i].autostate) { MySwitch[i].autostate = false; doSwitch(i, LOW); #ifndef DEBUG Serial.print("Auto OFF "); Serial.println(i); #endif } } } // void pressDetect(int ch, unsigned long p_stop) { if (MySwitch[ch].press_start != 0) { if ((p_stop-MySwitch[ch].press_start) < LONGPRESS) { // MySwitch[ch].press_stop = p_stop; #ifndef DEBUG Serial.print("Short press "); Serial.println(ch); #endif doSwitch(ch, MySwitch[ch].state ? LOW : HIGH); } else { // #ifndef DEBUG Serial.print("Long press "); Serial.println(ch); digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); #endif } } } // void chkLogic(){ /* ( /) 0- - / 1- - / 0 , 1.5 , 1 . 0 - 1 10 */ // 1,5 , - if ((onFlag == false) && (millis() > (MySwitch[0].power_on + 90000)) && (MySwitch[0].state == HIGH) && (MySwitch[1].state == LOW) && (MySwitch[1].press_stop < MySwitch[0].power_on)) { // doSwitch(1, HIGH); // onFlag = true; logicFlag = true; // MySwitch[1].autostate = false; #ifndef DEBUG Serial.println("Auto Logic ON"); #endif } // - - 10 if ((logicFlag == true) && (offFlag == false) && (MySwitch[1].state == HIGH) && (MySwitch[0].state == LOW)) { MySwitch[1].time_off = millis() + 600000; MySwitch[1].autostate = true; offFlag = true; #ifndef DEBUG Serial.println("Auto Logic OFF started"); #endif } // , if ((logicFlag == true) && (MySwitch[0].state == LOW) && (MySwitch[1].state == LOW)) { offFlag = false; onFlag = false; logicFlag = false; #ifndef DEBUG Serial.println("Logic reset"); #endif } // - if ((logicFlag == false) && (offFlag == false) && (MySwitch[0].press_stop > MySwitch[1].power_on) && (MySwitch[1].state == HIGH) && (MySwitch[0].state == LOW)) { logicFlag = true; #ifndef DEBUG Serial.println("Auto OFF 1 after manual OFF 0"); #endif } }
typedef struct{ float Value; // boolean Status; // // 0 - RO // 1 - RW char Note[16]; // } Parameter;
typedef struct{ int SensorID; // int CommandTo; // ... int Command; // // 0 - // 1 - // 2 - int ParamID; // float ParamValue; // boolean Status; // // 0 - (RO) // 1 - (RW) char Comment[16]; // } Message;
#define SID 701 // #define NumSensors 8 // Parameter MySensors[NumSensors+1] = { // ( ) NumSensors,0,"BR 2Floor", // 0,1,"Ch.1 (Light)", // 1 () 0,1,"Ch.2 (Vent)", // 2 () 0,1,"Ch.1 (LP)", // 1 0,1,"Ch.2 (LP)", // 2 0,1,"Auto-delayON", // ( ), 0,1,"Auto-delayOFF", // ( ), 0,1,"Ch.1 AutoOFF", // 1 , 0,1,"Ch.2 AutoOFF" // 2 , }; Message sensor;
// #include <avr/wdt.h> #include <Bounce.h> #include <SPI.h> #include "RF24.h" #include <EEPROM.h> #define DEBUG // - // #define CH 2 // #define LONGPRESS 2000 // 2 // #define SID 701 // #define NumSensors 8 // // "" typedef struct { int button; // int relay; // boolean state; // (/) unsigned long power_on; // , unsigned long auto_off; // , unsigned long time_off; // , boolean autostate; // , , unsigned long press_start; // , unsigned long press_stop; // , } Channel; // Channel MySwitch[CH] = { 15, 3, LOW, 0, 0, 0, false, 0, 0, 14, 4, LOW, 0, 0, 0, false, 0, 0 }; // typedef struct{ float Value; // boolean Status; // // 0 - RO // 1 - RW char Note[16]; // } Parameter; // typedef struct{ int SensorID; // int CommandTo; // ... int Command; // // 0 - // 1 - // 2 - int ParamID; // float ParamValue; // boolean Status; // // 0 - (RO) // 1 - (RW) char Comment[16]; // } Message; ///////////////////////////////////////////////////////////////////////////// Parameter MySensors[NumSensors+1] = { // ( ) NumSensors,0,"701 (2F, bath)", // "" 0,1,"Ch.1 (Light)", // 1 () 0,1,"Ch.2 (Vent)", // 2 () 0,1,"Ch.1 (LP)", // 1 0,1,"Ch.2 (LP)", // 2 0,1,"Auto-delayON", // ( ), 0,1,"Auto-delayOFF", // ( ), 0,1,"Ch.1 AutoOFF", // 1 , 0,1,"Ch.2 AutoOFF" // 2 , }; Message sensor; ///////////////////////////////////////////////////////////////////////////// // Bounce. , . Bounce bouncer0 = Bounce(MySwitch[0].button,5); Bounce bouncer1 = Bounce(MySwitch[1].button,5); // boolean logicFlag = false; boolean onFlag = false; boolean offFlag = false; //RF24 radio(CE,CSN); RF24 radio(10,9); unsigned long measureTime; #define DELTAMEASURE 15000 // 15 const uint64_t pipes[2] = { 0xF0F0F0F0A1LL, 0xF0F0F0F0A2LL }; volatile boolean waitRF24 = false; void setup() { wdt_disable(); // bootloop // EEPROM prepareFromEEPROM(); #ifndef DEBUG Serial.begin(9600); Serial.println("Start!"); pinMode(13, OUTPUT); #endif for(int i=0; i<CH; i++) { // pinMode(MySwitch[i].relay, OUTPUT); // pinMode(MySwitch[i].button, INPUT); // digitalWrite(MySwitch[i].button, HIGH); } // initRF24(); // ( - ) attachInterrupt(0, isr_RF24, FALLING); measureTime = millis()+DELTAMEASURE; //delay(5000); // , bootloop #ifndef DEBUG Serial.println("Ready!"); #endif wdt_enable (WDTO_8S); // 8 . } void loop() { // button_read(); // autoOff(); // chkLogic(); // listenRF24(); // - floodRF24(); // wdt_reset(); } void button_read(){ // 1 if ( bouncer0.update() ) { if ( bouncer0.read() == LOW) { // MySwitch[0].press_start = millis(); } else { // , ( ) , . pressDetect(0, millis()); } } // 2 if ( bouncer1.update() ) { if ( bouncer1.read() == LOW) { MySwitch[1].press_start = millis(); } else { //MySwitch[1].press_stop = millis(); pressDetect(1, millis()); } } } // void doSwitch(int ch, boolean state){ // MySwitch[ch].state = state; // "" if (MySwitch[ch].state == HIGH) { // MySwitch[ch].power_on = millis(); if((MySwitch[ch].auto_off > 0) && (MySwitch[ch].auto_off != 0)) { // , MySwitch[ch].time_off = MySwitch[ch].power_on + MySwitch[ch].auto_off; MySwitch[ch].autostate = true; } #ifndef DEBUG Serial.print("ON "); Serial.println(ch); #endif } else { // MySwitch[ch].autostate = false; // MySwitch[ch].time_off = 0; #ifndef DEBUG Serial.print("OFF "); Serial.println(ch); #endif } digitalWrite(MySwitch[ch].relay,MySwitch[ch].state); } // void autoOff(){ // for (int i=0; i < CH; i++) { // - if ((millis() >= MySwitch[i].time_off) && MySwitch[i].autostate) { MySwitch[i].autostate = false; doSwitch(i, LOW); #ifndef DEBUG Serial.print("Auto OFF "); Serial.println(i); #endif } } } // void pressDetect(int ch, unsigned long p_stop) { if (MySwitch[ch].press_start != 0) { if (((p_stop-MySwitch[ch].press_start) < LONGPRESS) && (p_stop-MySwitch[ch].press_start) > 0) { // MySwitch[ch].press_stop = p_stop; #ifndef DEBUG Serial.print("Short press "); Serial.println(ch); #endif doSwitch(ch, MySwitch[ch].state ? LOW : HIGH); } else { // #ifndef DEBUG Serial.print("Long press "); Serial.println(ch); digitalWrite(13, !digitalRead(13)); #endif // MySensors[ch+3].Value = 1; // "" // "" , - ( ) // "" } } } // void chkLogic(){ /* ( /) 0- - / 1- - / 0 , 1.5 , 1 . 0 - 1 10 */ // ( MySensors[5].Value - ), - if ((onFlag == false) && (millis() > (MySwitch[0].power_on + MySensors[5].Value*60000)) && (MySensors[5].Value != 0) && (MySwitch[0].state == HIGH) && (MySwitch[1].state == LOW) && (MySwitch[1].press_stop < MySwitch[0].power_on)) { // doSwitch(1, HIGH); // onFlag = true; logicFlag = true; // MySwitch[1].autostate = false; #ifndef DEBUG Serial.println("Auto Logic ON"); #endif } // - - (( MySensors[6].Value - ) if ((logicFlag == true) && (offFlag == false) && (MySensors[6].Value != 0) && (MySwitch[1].state == HIGH) && (MySwitch[0].state == LOW)) { MySwitch[1].time_off = millis() + MySensors[6].Value*60000; MySwitch[1].autostate = true; offFlag = true; #ifndef DEBUG Serial.println("Auto Logic OFF started"); #endif } // , if ((logicFlag == true) && (MySwitch[0].state == LOW) && (MySwitch[1].state == LOW)) { offFlag = false; onFlag = false; logicFlag = false; #ifndef DEBUG Serial.println("Logic reset"); #endif } // - if ((logicFlag == false) && (offFlag == false) && (MySwitch[0].press_stop > MySwitch[1].power_on) && (MySwitch[1].state == HIGH) && (MySwitch[0].state == LOW)) { logicFlag = true; #ifndef DEBUG Serial.println("Auto OFF 1 after manual OFF 0"); #endif } } void floodRF24(){ // (1 DELTAMEASURE ) // ! - ! if (millis() > measureTime){ getValue(); // //for (int i=1; i<=NumSensors; i++) { // (, - ) for (int i=1; i<=4; i++) { sendSlaveMessage(0, i); delay(20); } measureTime = millis()+DELTAMEASURE; } } void getValue(){ MySensors[1].Value = MySwitch[0].state; MySensors[2].Value = MySwitch[1].state; return; } // void isr_RF24(){ waitRF24 = true; } // (, , ) - (slave) // ! ParamID void sendSlaveMessage(int To, int ParamID) { // radio.stopListening(); radio.openWritingPipe(pipes[0]); radio.openReadingPipe(1,pipes[1]); delay(20); // sensor.SensorID = SID; sensor.CommandTo = To; sensor.Command = 0; sensor.ParamID = ParamID; sensor.ParamValue = MySensors[ParamID].Value; sensor.Status = MySensors[ParamID].Status; memcpy(&sensor.Comment,(char*)MySensors[ParamID].Note, 16); // RF24 bool ok = radio.write( &sensor, sizeof(sensor) ); delay (20); // radio.openWritingPipe(pipes[1]); radio.openReadingPipe(1,pipes[0]); radio.startListening(); } // void listenRF24(){ // , if (waitRF24) { waitRF24 = false; // , // if (radio.available()) { bool done = false; while (!done) { done = radio.read( &sensor, sizeof(sensor) ); // - if (sensor.CommandTo == SID) { // ( , , , ) doCommand(sensor.SensorID, sensor.Command, sensor.ParamID, sensor.ParamValue, sensor.Status, sensor.Comment); } } } } } // ( , , ID, , , ) - void doCommand(int From, int Command, int ParamID, float ParamValue, boolean Status, char* Comment) { // - , - switch (Command) { case 0: // break; case 1: getValue(); // sendSlaveMessage(From, ParamID); break; case 2: // setValue(From, ParamID, ParamValue, Comment); // sendSlaveMessage(From, ParamID); break; default: break; } } // (, , , ) void setValue(int From, int ParamID, float ParamValue, char* Comment) { // - if(MySensors[ParamID].Value != ParamValue){ // / - ( ) "" // "" ( ) if((ParamID<3) && (MySwitch[ParamID-1].state != (boolean)ParamValue)) { // " " MySwitch[ParamID-1].press_start = millis()-50; // " " ( "" ) pressDetect(ParamID-1, millis()); } else { // MySensors[ParamID].Value = ParamValue; // , - EEPROM if (ParamID > 4){ EEPROM.write(ParamID-5, MySensors[ParamID].Value); // if(ParamID > 6) { MySwitch[ParamID-7].auto_off = ((unsigned long)MySensors[ParamID].Value)*60000; } } } } } void initRF24(){ radio.begin(); radio.setRetries(15,15); // ( ) radio.setChannel(100); radio.openWritingPipe(pipes[0]); radio.openReadingPipe(1,pipes[1]); radio.startListening(); // } void prepareFromEEPROM() { // 4 = 4 1 : // 0 - ( ), // 1 - ( ), // 2 - 1 , // 3 - 2 , for(int i=0; i<4; i++) { MySensors[i+5].Value = EEPROM.read(i); } // for(int i=0; i<CH; i++) { MySwitch[i].auto_off = ((unsigned long)MySensors[i+7].Value)*60000; } }
Once again I will repeat my basic principle of the devices of my “smart home”: each created device is made to achieve a specific goal and it should work independently .
Source: https://habr.com/ru/post/215177/
All Articles