Kod: Zaznacz cały
#include <ESP8266WiFi.h>
/*
TODO:
- Forularz do wysylania ramki do ORNO i okno prezentacji wyniku (wszystko w HEX)
- chckbox do on/off zapytań do orno
- Forularz do prametrów transmisji formatu ramki
*/
//#define DEBUG
//----- Ustawienia UART -----//
#define DIR485 D0 // D2 na PCB
#define BAUD 9600
#define FORMAT_UART SERIAL_8E1
//----- Ustawienia sieci -----//
#define DHCP // uzycie definicji wlacza DHCP
#define WIFI_SSID "ssid"
#define WIFI_PASS "pass"
#ifndef DHCP // Gdy nie wlaczone DHCP
IPAddress staticIP(192, 168, 2, 101);
IPAddress gateway(192, 168, 2, 1);
IPAddress subnet(255, 255, 255, 0);
#endif
// #define DELAY_DIR // Deklaracja wlacza pauze przed po nadaniu ramki (przydatne gdy nie ma terminowalinia linii z polaryzacja)
#define TIM_SEND_BYTE_UART 1200 // Czas nadawania bajtu przez UART
#define DEF_RESTART_WIFI (5 * 60 * 10000) // 5 minut
WiFiServer localServer(8888);
WiFiClient localClient;
uint16_t Napiecie, WspolczynnikMocy, Czestotliwosc;
uint32_t Prad, MocCzynna, MocBierna, MocPozorna, EnergiaCzynna, EnergiaBierna;
uint32_t CzasDoResetu, CzasDoRstWifi, timeout485rx;
bool rdONROfull;
int8_t static pytanie = -1;
char static buf[10000];
//------------------------------------------------------------
#include "ESP8266WebServer.h"
ESP8266WebServer webServer(80);
//===========================================================
void IndexHandler()
{
// webServer.send("Location", "/index.html",true ); // przekierowanie na plik w SPIFFS
// webServer.send( 302,"text/plane" ); //EP 2018-12 str 31
// webServer.send( 200, "text/plain", "Czas uruchomienia " + String( millis()) + "ms" );
char txt[100];//1111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000
// strcpy( buf, "<head> <title>Licznik ORNO</title> <meta http-equiv='refresh' content='5' /> </head>" ); // Firefox burzy sie na 'refresh'
strcpy( buf, "<head> <title>Licznik ORNO</title> </head>" );
strcat( buf, "<H3>Licznik ORNO</H3><P>" );
sprintf( txt, "SysTick: %d sekund<P>", millis() / 1000 ); strcat( buf, txt );
#define TIM_OFLINE_ORNO 15000UL
if ( millis() < timeout485rx + TIM_OFLINE_ORNO ) { // Timeout 15 sekund
if ( rdONROfull ) {
sprintf( txt, "<font color='GREEN'><B> ON-Line </B> Read record %d", pytanie ); strcat( buf, txt );
}
else {
sprintf( txt, "<font color='ORANGE'><B> ON-Line </B> Read record %d", pytanie ); strcat( buf, txt );
}
}
else {
rdONROfull = false;
int tim = millis() - ( timeout485rx + TIM_OFLINE_ORNO);
if ( tim < 0 ) tim = 0;
sprintf( txt, "<font color='RED'> <B>OFF-Line </B> Time %d", tim / 1000 ); strcat( buf, txt );
}
sprintf( txt, "<P>Napiecie = %d,%02dV", Napiecie / 100, Napiecie % 100 ); strcat( buf, txt );
sprintf( txt, "<BR>Prad = %d,%03dA", Prad / 1000, Prad % 1000 ); strcat( buf, txt );
sprintf( txt, "<BR>Czestotliwosc=%d,%02dHz", Czestotliwosc / 100, Czestotliwosc % 100 ); strcat( buf, txt );
uint32_t MocSynchronizowana = MocCzynna + 1847900; // Dodajemy wskazanie licznie ZE
// MocSynchronizowana -= todo: odejmujemy bierzace (od resetu) z ORNO
sprintf( txt, "<P>MocCzynna = %d,%03dkW, ZE = %d,%03dkW ", MocCzynna / 1000, MocCzynna % 1000, MocSynchronizowana / 1000, MocSynchronizowana % 1000 ); strcat( buf, txt );
sprintf( txt, "<BR>MocBierna = %d,%03dkWAr", MocBierna / 1000, MocBierna % 1000 ); strcat( buf, txt );
sprintf( txt, "<BR>MocPozorna = %d,%03dkWA", MocPozorna / 1000, MocPozorna % 1000 ); strcat( buf, txt );
sprintf( txt, "<BR>WspolczynnikMocy = %d,%03d", WspolczynnikMocy / 1000, WspolczynnikMocy % 1000 ); strcat( buf, txt );
sprintf( txt, "<P>EnergiaCzynnaa = %d,%02dkWh", EnergiaCzynna / 100, EnergiaCzynna % 100 ); strcat( buf, txt );
sprintf( txt, "<BR>EnergiaBierna = %d,%02dkVArh", EnergiaBierna / 100, EnergiaBierna % 100 ); strcat( buf, txt );
strcat( buf, "</font>" );
//strcat( buf, "<P><A HREF='/s'>Skanuj I2C</A>" );
// webServer.send( 200, "text / plain", buf );
webServer.send( 200, "text/html; charset=iso-8859-2", buf );
/*
void send (int code, const String &content_type, const String &content)
void sendHeader (const String &name, const String &value, bool first=false)
void sendContent (const String &content)
*/
}
void notFoundHandler()
{
webServer.send( 404, "text/plain", "Strona nie istnieje." );
}
//w loop():
// webServer.handleClient();
//w setup():
// webServer.on( " / ", IndexHandler ); // tych deklaracji moze byc wiele,co by to nie znaczylo
// webServer.onNotFound( notFoundHandler );
// webServer.begin();
/*
boolean syncEventTriggered = false; // True if a time even has been triggered
NTPSyncEvent_t ntpEvent; // Last triggered event
int8_t timeZone = 1;
int8_t minutesTimeZone = 0;
bool wifiFirstConnected = false;
// Start NTP only after IP network is connected
void onSTAGotIP (WiFiEventStationModeGotIP ipInfo) {
Serial.printf ("***NTP*** Got IP: %s\r\n", ipInfo.ip.toString ().c_str ());
Serial.printf ("Connected: %s\r\n", WiFi.status () == WL_CONNECTED ? "yes" : "no");
wifiFirstConnected = true;
}
void onSTAConnected (WiFiEventStationModeConnected ipInfo) {
Serial.printf ("***NTP*** Connected to %s\r\n", ipInfo.ssid.c_str ());
}
// Manage network disconnection
void onSTADisconnected (WiFiEventStationModeDisconnected event_info) {
Serial.printf ("***NTP*** Disconnected from SSID: %s\n", event_info.ssid.c_str ());
Serial.printf ("Reason: %d\n", event_info.reason);
//NTP.stop(); // NTP sync can be disabled to avoid sync errors
}
void processSyncEvent(NTPSyncEvent_t ntpEvent) {
if (ntpEvent) {
Serial.print ("***NTP*** Time Sync error: ");
if (ntpEvent == noResponse)
Serial.println ("NTP server not reachable");
else if (ntpEvent == invalidAddress)
Serial.println ("Invalid NTP server address");
} else {
Serial.print ("***NTP*** Got NTP time: ");
Serial.println (NTP.getTimeDateString (NTP.getLastNTPSync ()));
}
}
*/
//===========================================================
uint16_t lenBufSerTx;
void setup() {
ESP.wdtEnable(1000);
Serial.begin(BAUD, FORMAT_UART);
WiFi.begin(WIFI_SSID, WIFI_PASS);
#ifndef DHCP
WiFi.mode(WIFI_STA);
WiFi.config(staticIP, gateway, subnet);
#endif
pinMode(DIR485, OUTPUT);
digitalWrite(DIR485, LOW);
Find_WiFi();
localServer.begin();
localServer.setNoDelay(true);
delay(100); // Czas na oproznienie bufora nadawczego UART
lenBufSerTx = Serial.availableForWrite();
#ifdef DEBUG
Serial.print( "\n\rBufor nadawczy UART "); Serial.print( lenBufSerTx ); Serial.println( " bajtow" );
#endif
webServer.on( "/", IndexHandler );
webServer.on( "/i", IndexHandler );
// webServer.on( "/s", IndexHandlerScan ); // podstrona WWW HTTP
webServer.onNotFound( notFoundHandler );
webServer.begin();
CzasDoRstWifi = millis() + DEF_RESTART_WIFI;
CzasDoResetu = millis() + 1 * 60 * 60 * 1000; // 24h //CzasDoResetu = millis() + 24 * 60 * 60 * 1000; // 24h
ESP.wdtEnable(100);
}
//------------------------------------------------------------
void Find_WiFi() {
Serial.print("\n\rRozlaczony, Lącze z sieca Wi-Fi '");
Serial.print( WIFI_SSID );
Serial.print("'...");
while (WiFi.status() != WL_CONNECTED) {
delay(200);
Serial.print(".");
}
Serial.print("\n\rPolaczony z siecia '");
Serial.print( WIFI_SSID );
Serial.print("' IP ");
Serial.print(WiFi.localIP());
Serial.print(". Tryb UART BRIDGE ");
Serial.flush();
Serial.println();
}
//------------------------------------------------------------
void wyslij_na_RS485( uint8_t *sbuf, size_t len) {
digitalWrite(DIR485, HIGH);
#ifdef DELAY_DIR
delay(1);
#endif
Serial.write(sbuf, len);
//delay(15); // Niestety trzeba dobrac doswiadczalnie bo zalezy od dlugosci ramki
// delay( len * 1.2 );//mozna tez czekac liczba bajtow x 1.2ms, bo wyslanie 1 bajtu przy 9600 8E1 trwa ok 0,0011458ms: 1/(9600/11)
while ( Serial.availableForWrite() != lenBufSerTx ) ; // Get the number of bytes (characters) available for writing in the serial buffer without blocking the write operation.
delayMicroseconds( TIM_SEND_BYTE_UART ); // Konieczne, bo uzywajac "Serial.availableForWrite()" stwierdzimy kiedy bufor jest pusty a nie kiedy znak wyslano z UART
#ifdef DELAY_DIR
delay(1);
#endif
digitalWrite(DIR485, LOW);
Serial.println();
}
//===========================================================
void loop() {
ESP.wdtFeed();
if ( millis() > CzasDoResetu ) {
Serial.print("\n\r*** Abort ***");
while ( Serial.availableForWrite() );
abort();
}
/*
if ( millis() > CzasDoRstWifi ) {
millis() + DEF_RESTART_WIFI;
Serial.println("***** Restart Wi-Fi *****");
disconnect
po kilkun sekundach connect
WiFi.begin();
}
*/
if (WiFi.status() != WL_CONNECTED) Find_WiFi();
if (localServer.hasClient()) {
if (!localClient.connected()) {
if (localClient) localClient.stop();
localClient = localServer.available();
}
}
//----- HTTP -----//
webServer.handleClient();
//----- Cykliczne odpytywanie licznika -----//
#define CO_ILE_PYTAC_ORNO 5000
const byte zapytanie[][8] =
{
{ 0x00, 0x03, 0x01, 0x31, 0x00, 0x01, 0xD5, 0xE8 }, // Pytanie o napiecie
{ 0x00, 0x03, 0x01, 0x39, 0x00, 0x02, 0x14, 0x2B }, // Pytanie o prad
{ 0x00, 0x03, 0x01, 0x40, 0x00, 0x02, 0xC5, 0xF2 }, // Pytanie o moc czynna
{ 0x00, 0x03, 0x01, 0x48, 0x00, 0x02, 0x44, 0x30 }, // Pytanie o moc bierna
{ 0x00, 0x03, 0x01, 0x58, 0x00, 0x01, 0x05, 0xF4 }, // Pytanie o PF
{ 0x00, 0x03, 0xA0, 0x00, 0x00, 0x0A, 0xE6, 0x1C }, // Pytanie o zuzyta energie czynna
{ 0x00, 0x03, 0xA0, 0x1E, 0x00, 0x0A, 0x86, 0x1A }, // Pytanie o zuzyta energie bierna
{ 0x00, 0x03, 0x01, 0x50, 0x00, 0x02, 0xC4, 0x37 }, // Pytanie o moc pozorna
{ 0x00, 0x03, 0x01, 0x30, 0x00, 0x01, 0x84, 0x28 }, // Pytanie o czestotliwosc
{ 0xFF }
};
int8_t static fl_Pytanie;
unsigned long static timeoutOdpytanie;
if ( millis() >= timeoutOdpytanie ) {
timeoutOdpytanie = millis() + CO_ILE_PYTAC_ORNO;
fl_Pytanie = true;
++pytanie;
if ( zapytanie[pytanie][0] != 0xFF ) wyslij_na_RS485( (uint8_t*)zapytanie[pytanie], 8 );
else pytanie = -1;
}
//----- WiFi->UART -----//
/*
if (localClient && localClient.connected()) {
if (localClient.available()) {
size_t len = localClient.available();
uint8_t sbuf[len];
localClient.readBytes(sbuf, len);
digitalWrite(DIR485, HIGH);
delay(2);
Serial.write(sbuf, len);
delay(15); // Niestety trzeba dobrac doswiadczalnie bo zalezy od dlugosci ramki
//mozna tez czekac liczba bajtow x 1.2ms, bo wyslanie 1 bajtu przy 9600 8E1 trwa ok 0,0011458ms: 1/(9600/11)
digitalWrite(DIR485, LOW);
}
}
*/
if (localClient && localClient.connected()) {
if (localClient.available()) {
timeoutOdpytanie = millis() + CO_ILE_PYTAC_ORNO * 2;
size_t len = localClient.available();
uint8_t sbuf[len];
localClient.readBytes(sbuf, len);
wyslij_na_RS485(sbuf, len);
}
}
//----- UART->WiFi -----//
/*
if (Serial.available()) {
delay(20); // Czekamy az wiecej znakow bedzie w buforze (przy 9600 ok 10)
size_t len = Serial.available();
uint8_t sbuf[len];
Serial.readBytes(sbuf, len);
if (localClient && localClient.connected()) {
localClient.write(sbuf, len);
}
}
*/
uint32_t static timeoutWr;
size_t static prevLen;
if ( prevLen != Serial.available() ) {
prevLen = Serial.available();
timeoutWr = millis() + 5; // Przychodzacy znak ustawia timeout
}
if ( millis() >= timeoutWr ) { // Gdy timeout minie
timeoutWr = 0xFFFFFFFF; // Zatrymujemy liczenie
size_t len = Serial.available();
uint8_t sbuf[len];
Serial.readBytes(sbuf, len);
if ( fl_Pytanie ) { // Jesli zapytanie lokalne (przez ESP)
fl_Pytanie = false;
timeout485rx = millis();
#ifdef DEBUG
char txt[50];
Serial.println( );
for ( byte x = 0; x < len; x++) {
sprintf( txt, " %02x", sbuf[x] );
Serial.print( txt );
}
#endif
// todo: sprawdzenie CRC
switch ( pytanie ) {
case 0: // Pytanie o napiecie
Napiecie = sbuf[3] << 8 | sbuf[4];
#ifdef DEBUG
sprintf( txt, "\n\rNapiecie=%d,%02d", Napiecie / 100, Napiecie % 100 ); Serial.println( txt );
#endif
break;
case 1: // Pytanie o prad
Prad = sbuf[3] << 24 | sbuf[4] << 16 | sbuf[5] << 8 | sbuf[6];
#ifdef DEBUG
sprintf( txt, "\n\rPrad=%d,%03d", Prad / 1000, Prad % 1000 ); Serial.println( txt );
#endif
break;
case 2: // Pytanie o moc czynna
MocCzynna = sbuf[3] << 24 | sbuf[4] << 16 | sbuf[5] << 8 | sbuf[6];
#ifdef DEBUG
sprintf( txt, "\n\rMocCzynna=%d,%03d", MocCzynna / 1000, MocCzynna % 1000 ); Serial.println( txt );
#endif
break;
case 3: // Pytanie o moc bierna
MocBierna = sbuf[3] << 24 | sbuf[4] << 16 | sbuf[5] << 8 | sbuf[6];
#ifdef DEBUG
sprintf( txt, "\n\rMocBierna=%d,%03d", MocBierna / 1000, MocBierna % 1000 ); Serial.println( txt );
#endif
break;
case 4: // Pytanie o PF
WspolczynnikMocy = sbuf[3] << 8 | sbuf[4];
#ifdef DEBUG
sprintf( txt, "\n\rWspolczynnikMocy=%d,%03d", WspolczynnikMocy / 1000, WspolczynnikMocy % 1000 ); Serial.println( txt );
#endif
break;
case 5: // Pytanie o zuzyta energie czynna
EnergiaCzynna = sbuf[3] << 24 | sbuf[4] << 16 | sbuf[5] << 8 | sbuf[6]; // Total, kolejne UINT32 to taryfy T1, T2, T3 i T4
#ifdef DEBUG
sprintf( txt, "\n\rEnergiaCzynnaa=%d,%02d", EnergiaCzynna / 100, EnergiaCzynna % 100 ); Serial.println( txt );
#endif
break;
case 6: // Pytanie o zuzyta energie bierna
EnergiaBierna = sbuf[3] << 24 | sbuf[4] << 16 | sbuf[5] << 8 | sbuf[6]; // Total, kolejne UINT32 to taryfy T1, T2, T3 i T4
#ifdef DEBUG
sprintf( txt, "\n\rEnergiaBierna=%d,%02d", EnergiaBierna / 100, EnergiaBierna % 100 ); Serial.println( txt );
#endif
break;
case 7: // Pytanie o moc pozorna
MocPozorna = sbuf[3] << 24 | sbuf[4] << 16 | sbuf[5] << 8 | sbuf[6];
#ifdef DEBUG
sprintf( txt, "\n\rMocPozorna=%d,%03d", MocPozorna / 1000, MocPozorna % 1000 ); Serial.println( txt );
#endif
break;
case 8: // Pytanie o czestotliwosc
Czestotliwosc = sbuf[3] << 8 | sbuf[4];
rdONROfull = true;
#ifdef DEBUG
sprintf( txt, "\n\rCzestotliwosc=%d,%02d", Czestotliwosc / 100, Czestotliwosc % 100 ); Serial.println( txt );
#endif
break;
}
}
else { // Zapytanie z Wi-Fi
if (localClient && localClient.connected()) {
localClient.write(sbuf, len);
}
}
}
}

Jak podłączyć RX i TX do MAX485 czy lepiej MAX3458 albo do odpowiednika nie trzeba się rozpisywać. Linia D2 płytki Wemos steruje wyprowadzeniami 2 i 3 drivera (wyprowadzenia DE i /RE). Linie A i B warto spolaryzować.