setStatusFuncImp to funkcja która jest wywoływana jak zmienia się stan połączenia z serwerem z wifi.
Jak zmienisz przyciskiem stan przekaźnika to serwer nie zostanie powiadomiony.
Coś źle nadal robisz jak masz takie opóźnienia. Może Cię rozłącza. Musisz sobie to bardziej precyzyjnie zdebugować.
Nie zmieniają się wszystkie stany za pomocą channelValueChanged
Dzięki tej funkcji chcę tylko ustawić zapisany stany przekaźnika w apce po nawiązaniu połączenia. Obsługę przekaźników mam zrobioną w SuplaDevice.setDigitalWriteFuncImpl.
Jeszcze raz dziękuje za pomoc
https://gui-generic-builder.supla.io/
Właśnie o coś takiego pytałemkrystianmen pisze: ↑pn cze 10, 2019 2:30 pm w setup() dodałem SuplaDevice.setStatusFuncImpl(&status_func) później:Chyba jest to już lepsze rozwiązanie niż moje pierwotne? Nie wiem jak bym miał do tego wykorzystać impl_arduino_timer.Kod: Zaznacz cały
void status_func(int status, const char *msg) { if ( status == 17 ) { Serial.println("wczytano stan przelacznikow"); SuplaDevice.channelValueChanged(0, read_supla_relay_state(0)); SuplaDevice.channelValueChanged(1, read_supla_relay_state(1)); SuplaDevice.channelValueChanged(2, read_supla_relay_state(2)); } }
EDIT: przy okazji to chyba dobre miejsce na sprawdzanie połączenia z serwerem:
if (status == STATUS_DISCONNECTED) {wejdź w tryb pracy samodzielnej - termostat, pompy itp.)
Hej,
Czy poradziliście sobie z tym problem. Piszę soft pod sterownik podlewania. Mam esp8266 i podłączoną do tego płytkę z 4 przekaźnikami (po i2c). Muszę to mieć tak napisane, że nigdy nie mogą się naraz włączyć dwa przekaźniki. Napisałem kod, który przełącza przekaźniki ale mam taki sam problem z aktualizacją statusu na serwerze i w aplikacji. Pojawiają się w opóźnieniem 25-30 sekund. Załóżmy, że działa przekaźnik 2 i chcę zmienić na 3. Klikam 3 i zmienia mi się aktywny przekaźnik. Jednocześnie wysyłam update na serwer no i zmuła 30s. Dodam, że jak będę klikał z apki ręcznie włącz wyłącz dany kanał to działa od razu. Tak samo ze strony działa od razu. Problem jest tylko z wysłanie stanu na serwer. Zmodyfikowałem kolejkę z srpc i nic. Zamieszczam też mój kod (nie jest skończony bo zblokowała mnie ta sprawa).
Czy poradziliście sobie z tym problem. Piszę soft pod sterownik podlewania. Mam esp8266 i podłączoną do tego płytkę z 4 przekaźnikami (po i2c). Muszę to mieć tak napisane, że nigdy nie mogą się naraz włączyć dwa przekaźniki. Napisałem kod, który przełącza przekaźniki ale mam taki sam problem z aktualizacją statusu na serwerze i w aplikacji. Pojawiają się w opóźnieniem 25-30 sekund. Załóżmy, że działa przekaźnik 2 i chcę zmienić na 3. Klikam 3 i zmienia mi się aktywny przekaźnik. Jednocześnie wysyłam update na serwer no i zmuła 30s. Dodam, że jak będę klikał z apki ręcznie włącz wyłącz dany kanał to działa od razu. Tak samo ze strony działa od razu. Problem jest tylko z wysłanie stanu na serwer. Zmodyfikowałem kolejkę z srpc i nic. Zamieszczam też mój kod (nie jest skończony bo zblokowała mnie ta sprawa).
Kod: Zaznacz cały
#define WDT D7
#define SW_1 D6
#define RS_1 D5
#include <srpc.h>
#include <log.h>
#include <eh.h>
#include <proto.h>
#include <IEEE754tools.h>
// We define our own ethernet layer
#define SUPLADEVICE_CPP
#include <SuplaDevice.h>
#include <lck.h>
//#include <WiFiClient.h>
//#include <ESP8266WiFiType.h>
#include <ESP8266WiFi.h>
//#include <ESP8266WiFiScan.h>
//#include <ESP8266WiFiMulti.h>
//#include <WiFiServer.h>
//#include <ESP8266WiFiGeneric.h>
//#include <WiFiClientSecure.h>
//#include <ESP8266WiFiAP.h>
//#include <ESP8266WiFiSTA.h>
//#include <WiFiUdp.h>
#include <ESP8266HTTPClient.h>
#include <TimeLib.h>
#include "PCF8574.h"
#include <LiquidCrystal_PCF8574.h>
#include <Wire.h>
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Hatak";
char password[] = "##################";
String buff;
//User variable
unsigned long previousMillisRelayAgent = 0, previousMillisDebug = 0, previousMillisLcdAgent = 0, previousMillisErrorAgent = 0;
uint8_t GLOBAL_STATE = 1, sinceRain = 0;
uint8_t buttonBounceBlocker = 0, buttonBounceBlocker2 = 0;
uint8_t currentRelayBoardState = 255;
uint8_t activeSection = 0;
uint16_t workTime = 0; //maksymalny czas pracy sterownika (ciągły czas podlewania)
uint8_t workTimeH = 0, workTimeM = 0, workTimeS = 0;
uint8_t error = 0; //flaga błedów
char line[60]; //zmienna wykorzystywana przy wyswietlaniu danych na lcd i nie tylko
unsigned long relayAgentTimeout = 0; //zmienna wykorzystywana przez agenta przekaźników
int heartbeat = LOW; //resetowanie zewnętrznego watchdoga
class BUTTON{
public:
uint8_t button; //przycisk
uint8_t state; //status przyciska
uint16_t pressTime;
unsigned long timeTick; //znacznik czasowy
BUTTON(uint8_t val_button = 0, uint8_t val_state = 0, uint16_t val_pressTime = 0, unsigned long val_timeTick = 0){
button = val_button;
state = val_state;
pressTime = val_pressTime;
timeTick = val_timeTick;
}
uint8_t checkButton();
};
uint8_t BUTTON::checkButton(){
if(!digitalRead(button)) { //obsługa przycisku
if((millis() >= timeTick)) {
timeTick = millis() + 50;
pressTime++;
if (pressTime >= 10) state = 2; //zwraca 2 jak klawisz wcisniety dluzej niz 5000ms (100*50)
}
}
else {
if ((pressTime > 0) && (pressTime < 10)) state = 1; //zwraca 1 jak klawisz wcisniety poniżej niz 5000ms (20*50)
else state = 0; //zwraca 0 jak klawisz nie wcisniety
pressTime = 0;
}
return state;
}
PCF8574 relayBoard(0x20);
LiquidCrystal_PCF8574 lcd(0x27);
BUTTON SW(SW_1, 0, 0, 0); //przycisk membranowy
WiFiClient client;
void setup()
{
// Debug console
Serial.begin(115200);
pinMode(SW_1, INPUT_PULLUP);
pinMode(RS_1, INPUT_PULLUP);
pinMode(WDT, OUTPUT);
relayBoard.begin();
relayBoard.write(1,HIGH); //realy 1 off
relayBoard.write(2,HIGH); //realy 2 off
relayBoard.write(3,HIGH); //realy 3 off
relayBoard.write(4,HIGH); //realy 4 off
relayBoard.write(5,HIGH); //realy 5 off
relayBoard.write(6,HIGH); //realy 6 off
relayBoard.write(7,HIGH); //realy 7 off
relayBoard.write(8,HIGH); //realy 8 off
//currentRelayBoardState = relayBoard.read8();
currentRelayBoardState = 255;
lcd.begin(20, 4); // initialize the lcd
lcd.setBacklight(255); //turn on backlight
WiFi.mode(WIFI_STA); // Force to station mode because if device was switched off while in access point mode it will start up next time in access point mode.
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.macAddress(mac);
char GUID[SUPLA_GUID_SIZE] = {mac[WL_MAC_ADDR_LENGTH - 6], mac[WL_MAC_ADDR_LENGTH - 5], mac[WL_MAC_ADDR_LENGTH - 4], mac[WL_MAC_ADDR_LENGTH - 3],
mac[WL_MAC_ADDR_LENGTH - 2], mac[WL_MAC_ADDR_LENGTH - 1], mac[WL_MAC_ADDR_LENGTH - 6], mac[WL_MAC_ADDR_LENGTH - 5],
mac[WL_MAC_ADDR_LENGTH - 4], mac[WL_MAC_ADDR_LENGTH - 3], mac[WL_MAC_ADDR_LENGTH - 2], mac[WL_MAC_ADDR_LENGTH - 1]};
SuplaDevice.addRelay(100); //włacznik główny
SuplaDevice.addSensorNO(RS_1); //czujnik deszczu NC
SuplaDevice.addRelay(101, false); //elektrozawór sekcja 1
SuplaDevice.addRelay(102, false); //elektrozawór sekcja 2
SuplaDevice.addRelay(103, false); //elektrozawór sekcja 3
SuplaDevice.addRelay(104, false); //elektrozawór sekcja 4
// SuplaDevice.addRelay(105, false);
// SuplaDevice.addRelay(106, false);
// SuplaDevice.addRelay(107, false);
// SuplaDevice.addRelay(108, false);
SuplaDevice.setDigitalReadFuncImpl(&supla_DigitalRead); // ------Send Value to server -------
SuplaDevice.setDigitalWriteFuncImpl(&supla_DigitalWrite); // ------- Read Value from server -------
// SuplaDevice.setTimerFuncImpl(&supla_timer);
// SuplaDevice.setStatusFuncImpl(&status_func); // ----------------------------- Status -----------------------------
SuplaDevice.setName("nawadniarka");
// // Replace the falowing GUID
// char GUID[SUPLA_GUID_SIZE] = {0x96,0x4D,0x66,0x3A,0x50,0x89,0xA0,0x64,0x0C,0x73,0x68,0x52,0x23,0xFF,0x99,0x0C};
// // with GUID that you can retrieve from https://www.supla.org/arduino/get-guid
// // Ethernet MAC address
// uint8_t mac[6] = {0x51, 0xef, 0x05, 0xf0, 0x9f, 0x00};
SuplaDevice.begin(GUID, // Global Unique Identifier
mac, // Ethernet MAC address
"suplacloud.herrero-net.com", // SUPLA server address
2, // Location ID
"XXXX"); // Location Password
//InfluxDB_save_bootUP(); //save to starbase boot up event
}
void loop()
{
if (heartbeat == LOW) heartbeat = HIGH; //kasowanie zewnętrznego watchdoga
else heartbeat = LOW;
digitalWrite(WDT, heartbeat);
SW.checkButton();
// if (GLOBAL_STATE && (SW.state == 2) && !buttonBounceBlocker2) {
// buttonBounceBlocker2 = 5;
// GLOBAL_STATE = 0;
// }
// else if (!GLOBAL_STATE && (SW.state == 2) && !buttonBounceBlocker2) {
// buttonBounceBlocker2 = 5;
// GLOBAL_STATE = 1;
// }
yield();
SuplaDevice.iterate();
if (GLOBAL_STATE && !error) relayAgent();
else if (!GLOBAL_STATE && !error) {
activeSection = 0;
relayAgent();
}
lcdAgent();
unsigned long currentMillisErrorAgent = millis(); //zabezpieczenie przed zbyt długą praca
if ((currentMillisErrorAgent - previousMillisErrorAgent) >= 1000) { //wykonuj co 1s
previousMillisErrorAgent = currentMillisErrorAgent;
if (activeSection && (workTime < 3600)) workTime++; //zwiekszanie licznik pracy (pojedyncza sekcja nie moze pracowac dłuzej niz 1h)
else if (activeSection && (workTime == 3600)) {
workTime++;
error = 1;
activeSection = 0;
relayAgent();
}
else workTime = 0;
//czujnik deszczu
if(digitalRead(RS_1)){
sinceRain = 0;
}
else sinceRain++;
}
}
void lcdAgent(){ //odswiezanie wyswietlacza
unsigned long currentMillis = millis();
if ((currentMillis - previousMillisLcdAgent) >= 1000) { //wykonuj co 1s
previousMillisLcdAgent = currentMillis;
lcd.home();
sprintf(line, "%02d.%02d.%04d %02d:%02d", day(), month(), year(), hour(), minute());
lcd.print(line);
lcd.setCursor(0,1);
sprintf(line, "Sekcja: %1d WT: %02dm%02ds", activeSection, workTime / 60, workTime % 60);
lcd.print(line);
lcd.setCursor(0,2);
if (sinceRain) sprintf(line, "Deszcz -> jest mokro");
else sprintf(line, "Od opadow: %03dd%02dg", sinceRain / (24*3600), sinceRain % (24*3600));
lcd.print(line);
lcd.setCursor(0,3);
if (error) sprintf(line, "Tryb: ERROR % 2ddBm", WiFi.RSSI());
else if (!client.connected()) sprintf(line, "Tryb: offline % 2ddBm", WiFi.RSSI());
else if (sinceRain) sprintf(line, "Tryb: pauza % 2ddBm", WiFi.RSSI());
else if (GLOBAL_STATE) sprintf(line, "Tryb: ON % 2ddBm", WiFi.RSSI());
else if (!GLOBAL_STATE) sprintf(line, "Tryb: OFF % 2ddBm", WiFi.RSSI());
lcd.print(line);
}
}
void relayAgent (){ //obsługa przekaźników sekcji
unsigned long currentMillis = millis();
if ((currentMillis - previousMillisRelayAgent) >= 1000) { //wykonuj co 1s
previousMillisRelayAgent = currentMillis;
uint8_t newRelayBoardState = 255; //domyślna wartość maski - wszystkie przekaźniki wyłaczone
if (activeSection) newRelayBoardState = ~(1 << (activeSection - 1)); //zmiana maski - wlaczenie wybranej sekcji (zero na odpowienie miejsce)
if (currentRelayBoardState == newRelayBoardState) return; //jeśli nie ma potrzeby nie zmieniaj stanu - wyjscie z funkcji
if (currentRelayBoardState == 255) { //zmiana stanu z wyłaczony na wybraną sekcję
relayBoard.write8(newRelayBoardState);
//currentRelayBoardState = relayBoard.read8(); //zapis aktualnego stanu
currentRelayBoardState = newRelayBoardState;
Serial.print("OFF -> ");
Serial.println(currentRelayBoardState, BIN);
supla_RelayValueChanged(); //synchronizacja z serwerem Supli
}
else if (currentRelayBoardState != 255) { //zmiana z włączonej sekcji na wyłączony (w kolejnym cyklu właczy się odpowienia sekcja)
relayBoard.write8(255);
//currentRelayBoardState = relayBoard.read8(); //zapis aktualnego stanu
currentRelayBoardState = 255;
Serial.print(currentRelayBoardState, BIN);
Serial.println(" - > OFF");
if (newRelayBoardState == 255) supla_RelayValueChanged(); //synchronizacja z serwerem Supli, tylko gdy nie będzie zmiany przekaźnika
}
}
}
void supla_RelayValueChanged(){
//uint8_t currentRelayBoardState = relayBoard.read8();
SuplaDevice.channelValueChanged(2, !(currentRelayBoardState & 0x01));
SuplaDevice.channelValueChanged(3, !(currentRelayBoardState & 0x02));
SuplaDevice.channelValueChanged(4, !(currentRelayBoardState & 0x04));
SuplaDevice.channelValueChanged(5, !(currentRelayBoardState & 0x08));
// SuplaDevice.channelValueChanged(7, !(currentRelayBoardState & 0x10));
// SuplaDevice.channelValueChanged(8, !(currentRelayBoardState & 0x20));
// SuplaDevice.channelValueChanged(9, !(currentRelayBoardState & 0x40));
// SuplaDevice.channelValueChanged(10, !(currentRelayBoardState & 0x80));
}
void InfluxDB_save_bootUP(){
String data;
data += "ctrl_ogrod,";
data += "sensor=bootUP";
data += " value=1";
//Serial.println(data);
HTTPClient http;
http.begin("http://10.10.10.250:8086/write?db=starbase&precision=s&u=starsystem&p=XXXXX");
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
http.POST(data);
//http.writeToStream(&data);
http.end();
}
// void InfluxDB_save_state(){
// String data;
// data += "ctrl_ogrod,";
// data += "sensor=Sx";
// switch (activeSection) {
// case 0:
// data += " value=0";
// break;
// case 1:
// data += " value=1";
// break;
// case 2:
// data += " value=2";
// break;
// case 3:
// data += " value=3";
// break;
// case 4:
// data += " value=4";
// break;
// }
// // data += "sensor=S1";
// // if (activeSection == 1)data += " value=1";
// // else data += " value=0";
// // data += '\n';
// // data += "ctrl_ogrod,";
// // data += "sensor=S2";
// // if (activeSection == 2) data += " value=1";
// // else data += " value=0";
// // data += '\n';
// // data += "ctrl_ogrod,";
// // data += "sensor=S3";
// // if (activeSection == 3) data += " value=1";
// // else data += " value=0";
// // data += '\n';
// // data += "ctrl_ogrod,";
// // data += "sensor=S4";
// // if (activeSection == 4) data += " value=1";
// // else data += " value=0";
// data += '\n';
// data += "ctrl_ogrod,";
// data += "sensor=autoMode";
// if (autoMode == 1) data += " value=1";
// else data += " value=0";
// data += '\n';
// data += "ctrl_ogrod,";
// data += "sensor=globalState";
// if (GLOBAL_STATE == 1) data += " value=1";
// else data += " value=0";
// data += '\n';
// data += "ctrl_ogrod,";
// data += "sensor=rainSensor";
// if (digitalRead(RS_1) == 1) data += " value=1";
// else data += " value=0";
// //Serial.println(data);
// HTTPClient http;
// http.begin("http://10.10.10.250:8086/write?db=starbase&precision=s&u=starsystem&p=tst12xvn");
// http.addHeader("Content-Type", "application/x-www-form-urlencoded");
// http.POST(data);
// //http.writeToStream(&data);
// http.end();
// }
//#########################################################################################################
// Supla.org ethernet layer
int supla_arduino_tcp_read(void *buf, int count) {
_supla_int_t size = client.available();
if ( size > 0 ) {
if ( size > count ) size = count;
return client.read((uint8_t *)buf, size);
};
return -1;
};
int supla_arduino_tcp_write(void *buf, int count) {
return client.write((const uint8_t *)buf, count);
};
bool supla_arduino_svr_connect(const char *server, int port) {
return client.connect(server, 2015);
}
bool supla_arduino_svr_connected(void) {
return client.connected();
}
void supla_arduino_svr_disconnect(void) {
client.stop();
}
void supla_arduino_eth_setup(uint8_t mac[6], IPAddress *ip) {
// Serial.println("WiFi init");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
// Serial.print(".");
}
//Serial.print("\nlocalIP: ");
//Serial.println(WiFi.localIP());
//Serial.print("subnetMask: ");
//Serial.println(WiFi.subnetMask());
//Serial.print("gatewayIP: ");
//Serial.println(WiFi.gatewayIP());
}
SuplaDeviceCallbacks supla_arduino_get_callbacks(void) {
SuplaDeviceCallbacks cb;
cb.tcp_read = &supla_arduino_tcp_read;
cb.tcp_write = &supla_arduino_tcp_write;
cb.eth_setup = &supla_arduino_eth_setup;
cb.svr_connected = &supla_arduino_svr_connected;
cb.svr_connect = &supla_arduino_svr_connect;
cb.svr_disconnect = &supla_arduino_svr_disconnect;
cb.get_temperature = NULL;
cb.get_temperature_and_humidity = NULL;
cb.get_rgbw_value = NULL;
cb.set_rgbw_value = NULL;
return cb;
}
int supla_DigitalRead(int channelNumber, uint8_t pin) {
int result = 0;
if ((pin >= 101) && (pin <=108)) {
if ((pin == 101) && (activeSection == 1)) result = 1;
else if ((pin == 102) && (activeSection == 2)) result = 1;
else if ((pin == 103) && (activeSection == 3)) result = 1;
else if ((pin == 104) && (activeSection == 4)) result = 1;
else result = 0;
Serial.print("Supla Read(");
Serial.print(pin);
Serial.print("): ");
Serial.println(result);
}
else if (pin == 100) {
if (GLOBAL_STATE) result = 1;
else result = 0;
}
else result = digitalRead(pin);
return result;
}
void supla_DigitalWrite(int channelNumber, uint8_t pin, uint8_t val) {
Serial.print("Supla Write(");
Serial.print(channelNumber);
Serial.print(",");
Serial.print(pin);
Serial.print(",");
Serial.print(val);
Serial.println(")");
if ((pin >= 101) && (pin <=108)) {
if ((pin == 101) && val) activeSection = 1;
else if ((pin == 102) && val) activeSection = 2;
else if ((pin == 103) && val) activeSection = 3;
else if ((pin == 104) && val) activeSection = 4;
else activeSection = 0;
}
else if (pin == 100) {
if (val) GLOBAL_STATE = 1;
else GLOBAL_STATE = 0;
}
else digitalWrite(pin, val);
}
void status_func(int status, const char *msg) {
if (status == 17) {
Serial.println("zapis na serwer Supla");
//SuplaDevice.channelValueChanged(1, digitalRead(POWER));
}
}
you can't send everything at once.
this does not work:
or you send only those that have changed (with 2 channel simultaneous it worked fine) or in a sequence one channel in each main loop.
this does not work:
Kod: Zaznacz cały
void supla_RelayValueChanged(){
//uint8_t currentRelayBoardState = relayBoard.read8();
SuplaDevice.channelValueChanged(2, !(currentRelayBoardState & 0x01));
SuplaDevice.channelValueChanged(3, !(currentRelayBoardState & 0x02));
SuplaDevice.channelValueChanged(4, !(currentRelayBoardState & 0x04));
SuplaDevice.channelValueChanged(5, !(currentRelayBoardState & 0x08));
// SuplaDevice.channelValueChanged(7, !(currentRelayBoardState & 0x10));
// SuplaDevice.channelValueChanged(8, !(currentRelayBoardState & 0x20));
// SuplaDevice.channelValueChanged(9, !(currentRelayBoardState & 0x40));
// SuplaDevice.channelValueChanged(10, !(currentRelayBoardState & 0x80));
}
or you send only those that have changed (with 2 channel simultaneous it worked fine) or in a sequence one channel in each main loop.
Dziękuję za pomoc. Teraz wysyłam tylko to co jest konieczne i działa. Mam jeszcze jedno pytanie. Jak elegancko ustawić statusy na serwerze hurtem po restarcie. Czy użycie callback jak to proponuje krych88 jest poprawne i eleganckie?
krycha88 pisze: ↑pn cze 10, 2019 2:30 pm w setup() dodałem SuplaDevice.setStatusFuncImpl(&status_func) później:Chyba jest to już lepsze rozwiązanie niż moje pierwotne? Nie wiem jak bym miał do tego wykorzystać impl_arduino_timer.Kod: Zaznacz cały
void status_func(int status, const char *msg) { if ( status == 17 ) { Serial.println("wczytano stan przelacznikow"); SuplaDevice.channelValueChanged(0, read_supla_relay_state(0)); SuplaDevice.channelValueChanged(1, read_supla_relay_state(1)); SuplaDevice.channelValueChanged(2, read_supla_relay_state(2)); } }