/** monitor Solis inverter with ESP8266 and 1602 I2C LCD display SCL to D1 | SDA to D2 | Gnd to GND | Vcc to 3V or VV (but NOT Vin) */ #include #include #include #include #include #include // uncomment next two lines for large Display ( 20x4 ) // bool largeDisplay = true; // LiquidCrystal_I2C lcd(0x3F, 20, 4); // set the LCD I2C address to 0x3F (typical for 20x4) // uncomment for small display ( 16x2 ) bool largeDisplay = false; LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD I2C address to 0x27 (typical for 16x2) // If you don't see anything on the display, there are a few things to check: // - there is usually an LED on the display, is it on? Check power. // - the contrast might be too low, there's a screw adjustment on the back // - it might be very dim - there's usually a link on the LCD's board that enables the backlight // - You might be using the wrong address - run an I2C scan (plenty of examples online) int screenWidth; int screenHeight; String msg; String daily = " No daily power "; // end of day message; initialised for starting with no history ESP8266WiFiMulti WiFiMulti; // We will use a simple spinner to indicate that the display is waiting using |/-\ // We'll define a couple of special characters for the LCD displays. // Backslash "\" is usually displayed as a Japanese character // We'll also create a solid fill block for flashing. byte slash[8] = { B00000, B10000, B01000, B00100, B00010, B00001, B00000, }; byte fill[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, }; char now[8]; // current power display char day[8]; // daily power display char spin[] = {124, 47, 45, 0, 1}; // characters used for spinner void setup() { Serial.begin(115200); Serial.println(); if (largeDisplay) { screenWidth = 20; // Screen width (in characters) screenHeight = 4; // Screen height (in characters) } else { screenWidth = 16; // Screen width (in characters) screenHeight = 2; // Screen height (in characters) } lcd.init(); // initialize the lcd lcd.begin(screenWidth, screenHeight); lcd.backlight(); lcd.createChar(0, slash); // character 0 for backslash lcd.createChar(1, fill); // character 1 for solid block lcd.clear(); // clear the screen lcd.setCursor(0, 0); // move top left lcd.print("Alisdair's"); // print intro text lcd.setCursor(0, 1); // lcd.print("Solar Inverter"); // for (uint8_t t = 4; t > 0; t--) { Serial.printf("[SETUP] WAIT %d...\n", t); Serial.flush(); delay(1000); } WiFi.mode(WIFI_STA); // replace your WiFi SSID and PASSWORD below WiFiMulti.addAP("SSID", "PASSWORD"); lcd.clear(); } void loop() { // wait for WiFi connection if ((WiFiMulti.run() == WL_CONNECTED)) { WiFiClient client; HTTPClient http; // read status page from Solis WiFi dongle // replace your login, password and Solis dongle's IP address below if (http.begin(client, "http://user:password@Solis_wifi_IP/status.html")) { // HTTP // Serial.print("[HTTP] GET...\n"); // start connection and send HTTP header int httpCode = http.GET(); // httpCode will be negative on error if (httpCode > 0) { // file found at server if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { String payload = http.getString(); // Serial.println(payload); // uncomment if you want to see the web page code on the console lcd.clear(); Serial.println("=============="); Serial.println("== SOLAR PANELS =="); if (largeDisplay) { msg = "--- SOLAR PANELS ---"; lcd.setCursor(0, 0); lcd.print(msg); } else { // nothing for small display } // nowloc is position of NOW power value in Solis status page int nowloc = payload.indexOf("var webdata_now_p") ; // strip the value from the web page into a new String String nowcropped = payload.substring(nowloc + 21, nowloc + 27); // and put it in a char array nowcropped.toCharArray(now, 7); // replace any unwanted characters with spaces for (int c = 0; c < 7; c++) { if (now[c] == '"' || now[c] == ';' || now[c] < ' ' ) { now[c] = ' '; } } Serial.print( " NOW (W) : " ); Serial.print( now ); if (largeDisplay) { msg = " NOW (W) : " + String(now) ; lcd.setCursor(0, 2); lcd.print(msg); } else { msg = "NOW (W) " + String(now) ; lcd.setCursor(0, 0); lcd.print(msg); } Serial.println(); //repeat the above for DAILY power value int dayloc = payload.indexOf("var webdata_today_e") ; String daycropped = payload.substring(dayloc + 23, dayloc + 29); daycropped.toCharArray(day, 7); for (int c = 0; c < 7 ; c++) { if (day[c] == '"' || day[c] == ';' || day[c] < ' ' ) { day[c] = ' '; } } Serial.print( "DAY (KWh) : " ); Serial.print( day ); if (largeDisplay) { msg = " DAY (KWh) : " + String(day) ; daily = msg; // keep for no signal lcd.setCursor(0, 3); lcd.print(msg); } else { msg = "DAY (KWh) " + String(day) ; daily = msg; // keep for no signal lcd.setCursor(0, 1); lcd.print(msg); } Serial.println(); } } else { Serial.println("== SOLAR PANELS =="); Serial.println("== NO =="); Serial.println("== CONNECTION =="); if (largeDisplay) { msg = "-- SOLAR PANELS --"; lcd.setCursor(0, 0); lcd.print(msg); msg = "== NO SIGNAL =="; lcd.setCursor(0, 1); lcd.print(msg); lcd.setCursor(0, 3); lcd.print(daily); // latest daily total } else { msg = "Solar:No signal"; lcd.setCursor(0, 0); lcd.print(msg); lcd.setCursor(0, 1); lcd.print(daily); // latest daily total } } http.end(); } } spinner(); } // spinner is visual indicator, flash indicates an update void spinner() { for (int loop = 0; loop < 15; loop++) { for (int c = 0 ; c < 4 ; c++) { if (largeDisplay) { lcd.setCursor(19, 3); } else { lcd.setCursor(15, 0); } lcd.print(spin[c]); delay(500); } } if (largeDisplay) { lcd.setCursor(19, 3); } else { lcd.setCursor(15, 0); } lcd.print(spin[4]); }