123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- /*
- * WebSocketClient.ino
- *
- * Created on: 24.05.2015
- *
- */
-
- //#include <Arduino.h>
- #include <M5Stack.h>
- #include <ArduinoJson.h>
- #include <WiFi.h>
- #include <WiFiMulti.h>
- #include <WiFiClientSecure.h>
-
- #include <HttpClient.h>
-
- #include <WebSocketsClient.h>
-
-
- WiFiMulti WiFiMulti;
- WebSocketsClient webSocket;
-
- HttpClient htclient;
-
- bool localTesting = true;
- bool genRandomVals = false;
-
- const char* OVMSUSER = "admin";
- const char* OVMSPASS = "OVMSP455w0rd"; // Change this to your password
-
- const int LCDBrightnessSteps[] = {60, 120, 250};
- int LCDBrightnessStep = 0;
-
- const int heightBarGraphSOC = 72;
- const int widthBarGraphSOC = 300;
- const int leftBarGraphSOC = (320-widthBarGraphSOC-4)/2;
- const int topBarGraphSOC = 0;
- const int SOCtextSize = 7;
- const int SOCtextWidth = M5.Lcd.textWidth("99%")*SOCtextSize;
-
- const int heightBarGraphPWR = 32;
- const int widthBarGraphPWR = 220;
- const int PWRtextSize = 3;
- const int PWRtextWidth = M5.Lcd.textWidth("100kW")*PWRtextSize;
- const int leftBarGraphPWR = (320-widthBarGraphPWR-4);
- const int topBarGraphPWR = 80;
-
- const int topTextLineRange = topBarGraphPWR + heightBarGraphPWR + 16;
- const int topTextLineConsumption = topTextLineRange + 32;
- const int topTextLineTemps = topTextLineConsumption + 32;
-
- const float MAXINPOWER = 100;
- const float MAXOUTPOWER = 200;
- const float MAXRANGEPWR = 300;
-
- float vbsoc = 90.5;
- float vbrangeideal = 402 ;
- float vbrangefull = 450 ;
- float vetemp = 13 ;
- float vbtemp = 15 ;
- float xknbinlettemp = 14 ;
- float vbpower = 1 ;
- float vbconsumption = 160 ;
-
- const uint16_t DARKERCYAN = 0x0124;
-
- const size_t jsonCapacity = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(38) + 910;
- DynamicJsonDocument jsonDoc(jsonCapacity);
- DeserializationError payloadDecodeError;
- uint8_t M5triggerUpdate = 0;
-
- uint8_t dummyCounter = 0;
-
- unsigned long prevTimer = millis();
- unsigned long displayTimer = millis();
- unsigned long spentTimer = 0;
- bool slowRefreshTrigger = false;
- unsigned long slowRefreshTimer = 0;
- unsigned long slowRefreshMax = 5000;
- bool mildRefreshTrigger = false;
- unsigned long mildRefreshTimer = 0;
- unsigned long mildRefreshMax = 2000;
- bool fastRefreshTrigger = false;
- unsigned long fastRefreshTimer = 0;
- unsigned long fastRefreshMax = 100;
-
- #define USE_SERIAL Serial
-
- void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
- const uint8_t* src = (const uint8_t*) mem;
- USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
- for(uint32_t i = 0; i < len; i++) {
- if(i % cols == 0) {
- USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
- }
- USE_SERIAL.printf("%02X ", *src);
- src++;
- }
- USE_SERIAL.printf("\n");
- }
-
- void draw_vbsoc(float vbsoc) {
- M5.Lcd.setTextSize(SOCtextSize);
- uint16_t SOCcolor = GREEN;
- uint16_t SOCtextColor = 0x0720; // Slightly Darker Green
- uint16_t BorderColor = WHITE;
- uint16_t BGcolor = 0x2970; //BLUE;
- if(vbsoc<25){ SOCcolor = YELLOW; SOCtextColor = YELLOW; BorderColor = YELLOW; }
- if(vbsoc<10){ SOCcolor = RED; SOCtextColor = RED; BorderColor = RED; BGcolor = MAROON; }
- M5.Lcd.fillRoundRect(leftBarGraphSOC, topBarGraphSOC, widthBarGraphSOC+6, heightBarGraphSOC+4 , 6, BGcolor);
- //M5.Lcd.fillRect(leftBarGraphSOC, topBarGraphSOC, widthBarGraphSOC+4, heightBarGraphSOC+4 , BGcolor);
- M5.Lcd.drawRoundRect(leftBarGraphSOC, topBarGraphSOC, widthBarGraphSOC+4, heightBarGraphSOC+4 , 6, BorderColor);
- M5.Lcd.fillRoundRect(leftBarGraphSOC+2, topBarGraphSOC+2, widthBarGraphSOC*(vbsoc/100), heightBarGraphSOC , 4, SOCcolor);
- if(vbsoc>=50){
- M5.Lcd.setTextColor(BLACK);
- M5.Lcd.setCursor(leftBarGraphSOC+6+3*vbsoc-SOCtextWidth-6, topBarGraphSOC+14);
- M5.Lcd.print(vbsoc,0); M5.Lcd.print('%');
- }else{
- M5.Lcd.setTextColor(SOCtextColor);
- M5.Lcd.setCursor(leftBarGraphSOC+6+3*vbsoc+8, topBarGraphSOC+12);
- M5.Lcd.print(vbsoc,0); M5.Lcd.print('%');
- }
- //M5.Lcd.printf("%*s", 5, vbsoc);
- M5triggerUpdate++;
- }
-
- void draw_vbpower(float vbpower) {
- M5.Lcd.setTextSize(PWRtextSize);
- uint16_t PWRcolor;
-
- uint16_t BorderColor = LIGHTGREY; //WHITE;
- uint16_t BGcolor = 0x528A;
-
- // Draw empty full bar
- M5.Lcd.fillRoundRect(leftBarGraphPWR, topBarGraphPWR, widthBarGraphPWR+6, heightBarGraphPWR+4 , 6, BGcolor);
- //M5.Lcd.fillRect(leftBarGraphSOC, topBarGraphSOC, widthBarGraphSOC+4, heightBarGraphSOC+4 , BGcolor);
- M5.Lcd.drawRoundRect(leftBarGraphPWR, topBarGraphPWR, widthBarGraphPWR+4, heightBarGraphPWR+4 , 6, BorderColor);
- float barOffset;
- float barWidth;
-
- if(vbpower>0){
- PWRcolor = YELLOW; if(vbpower>25) PWRcolor = RED;
- barWidth = (widthBarGraphPWR*vbpower)/MAXRANGEPWR;
- // (220*140)/220
- barOffset = (widthBarGraphPWR*(float)MAXINPOWER)/MAXRANGEPWR;
- } else {
- PWRcolor = GREEN;
- barWidth = (widthBarGraphPWR*-vbpower)/MAXRANGEPWR;
- barOffset = (widthBarGraphPWR*((float)MAXINPOWER+vbpower))/MAXRANGEPWR;
- }
- // USE_SERIAL.print(barOffset); USE_SERIAL.print(" "); USE_SERIAL.println(barWidth);
-
- // Draw Power Bar
- //M5.Lcd.fillRoundRect(leftBarGraphPWR+2+barOffset, topBarGraphPWR+2, barWidth, heightBarGraphPWR , 4, PWRcolor);
- M5.Lcd.fillRect(leftBarGraphPWR+2+barOffset, topBarGraphPWR+2, barWidth, heightBarGraphPWR, PWRcolor);
-
- // Clean text
- M5.Lcd.fillRoundRect(4, topBarGraphPWR, PWRtextWidth, heightBarGraphPWR+4 , 6, BLACK);
-
- // Place 0 line
- M5.Lcd.drawLine(
- leftBarGraphPWR+2+(widthBarGraphPWR*(float)MAXINPOWER)/MAXRANGEPWR,
- topBarGraphPWR,
- leftBarGraphPWR+2+(widthBarGraphPWR*(float)MAXINPOWER)/MAXRANGEPWR,
- topBarGraphPWR+heightBarGraphPWR+2,
- BorderColor);
-
- M5.Lcd.setCursor(4, topBarGraphPWR+8);
- if(vbpower>0){
- M5.Lcd.setTextColor(RED);
- }else{
- M5.Lcd.setTextColor(GREEN);
- }
- if(vbpower > 0 && vbpower < 10 ) M5.Lcd.print(" ");
- if(vbpower > -10 && vbpower < 100 ) M5.Lcd.print(" ");
-
- M5.Lcd.print(vbpower,0); M5.Lcd.print("kW");
- //M5.Lcd.drawFloat(vbpower, 0, 4, topBarGraphPWR+8);
- //M5.Lcd.drawNumber(vbpower, 4, topBarGraphPWR+8);
- //M5.Lcd.print('kW');
- //M5.Lcd.printf("%*s", 5, vbpower);
- M5triggerUpdate++;
- }
-
- void draw_vbrange() {
- M5.Lcd.setTextSize(3);
- M5.lcd.fillRect(0, topTextLineRange, 320,32, DARKERCYAN);
- M5.Lcd.setCursor(4, topTextLineRange+4);
- M5.Lcd.setTextColor(LIGHTGREY);
- M5.Lcd.print("range: "); M5.Lcd.print(vbrangeideal,0); M5.Lcd.print("/");
- M5.Lcd.print(vbrangefull,0); M5.Lcd.print(" km");
- M5triggerUpdate++;
- }
-
- void draw_vbconsumption() {
- uint16_t textColor = GREEN;
- if(vbconsumption>150) textColor = YELLOW;
- if(vbconsumption>200) textColor = RED;
- M5.Lcd.setTextSize(3);
- M5.lcd.fillRect(0, topTextLineConsumption, 320,32, DARKERCYAN);
- M5.Lcd.setCursor(4, topTextLineConsumption+4);
- M5.Lcd.setTextColor(LIGHTGREY);
- M5.Lcd.print("cons: ");
- M5.Lcd.setTextColor(textColor);
- M5.Lcd.print(vbconsumption,0);
- M5.Lcd.setTextColor(LIGHTGREY);
- M5.Lcd.print(" Wh/km");
- M5triggerUpdate++;
- }
-
- void draw_temps() {
- M5.Lcd.setTextSize(2);
- M5.lcd.fillRect(0, topTextLineTemps,320 , 24, DARKERCYAN);
- M5.Lcd.setCursor(4, topTextLineTemps+4);
- M5.Lcd.setTextColor(LIGHTGREY); M5.Lcd.print("temps ext:");
- M5.Lcd.print(vetemp,0);
- M5.Lcd.setTextColor(LIGHTGREY); M5.Lcd.print(" in:");
- M5.Lcd.print(xknbinlettemp,0);
- M5.Lcd.setTextColor(LIGHTGREY); M5.Lcd.print(" bt:");
- M5.Lcd.print(vbtemp,0);
- M5triggerUpdate++;
- }
-
- void tickerBox(uint16_t tickerColor) {
- M5.lcd.fillRect(0,240-6 ,4 ,4 , tickerColor);
- M5triggerUpdate++;
- }
-
- void changeLCDBrightness() {
- LCDBrightnessStep++;
- if(LCDBrightnessStep==3) LCDBrightnessStep=0;
- M5.Lcd.setBrightness(LCDBrightnessSteps[LCDBrightnessStep]);
- if(localTesting) USE_SERIAL.printf("[LCD] Setting Brightness to : %u (step %u)\n", LCDBrightnessSteps[LCDBrightnessStep], LCDBrightnessStep);
- }
-
- void sendButtonA() {
- sendEvent("event+raise+M5.button.A");
- }
-
- void sendButtonB() {
- sendEvent("event+raise+M5.button.B");
- }
-
- void sendEvent(char* event){
- M5.Lcd.fillRect(0, 220, 320, 32, BLUE);
- M5.Lcd.setCursor(6, 222);
- M5.Lcd.setTextColor(YELLOW);
- M5.Lcd.setTextSize(2);
- M5.Lcd.print(event);
- M5.update();
- M5triggerUpdate = 0;
-
- WiFiClient client;
- if (!client.connect("192.168.4.1", 80 )) {
- Serial.println("connection failed");
- return;
- }
- String url = "/api/execute?apikey=";
- url += OVMSPASS;
- url += "&command=";
- url += event;
- USE_SERIAL.print("Requesting URL: ");
- USE_SERIAL.println(url);
-
- client.print(String("GET ") + url + " HTTP/1.1\r\n" +
- "Host: 192.168.4.1\r\n" +
- "Connection: close\r\n\r\n");
- unsigned long timeout = millis();
- while (client.available() == 0) {
- if (millis() - timeout > 5000) {
- USE_SERIAL.println(">>> Client Timeout !");
- client.stop();
- return;
- }
- }
- while(client.available()) {
- String line = client.readStringUntil('\r');
- USE_SERIAL.print(line);
- }
-
- Serial.println();
- Serial.println("closing connection");
-
- M5.Lcd.fillRect(0, 220, 320, 32, BLACK);
- M5.update();
- M5triggerUpdate = 0;
- }
-
- void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
-
- // Timer control
- prevTimer=displayTimer;
- displayTimer=millis();
- spentTimer=displayTimer-prevTimer;
- slowRefreshTimer+=spentTimer;
- mildRefreshTimer+=spentTimer;
- fastRefreshTimer+=spentTimer;
- slowRefreshTrigger = (slowRefreshTimer>=slowRefreshMax) ? true : false;
- mildRefreshTrigger = (mildRefreshTimer>=mildRefreshMax) ? true : false;
- fastRefreshTrigger = (fastRefreshTimer>=fastRefreshMax) ? true : false;
-
- switch(type) {
- case WStype_DISCONNECTED:
- USE_SERIAL.printf("[WSc] Disconnected!\n");
- tickerBox(RED); M5.update();
- break;
- case WStype_CONNECTED:
- tickerBox(YELLOW); M5.update();
- if(localTesting) USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
- // send message to server when Connected
- //webSocket.sendTXT("M5 Stack Connected");
- sendEvent("event+raise+M5.websocket.connected");
- break;
- case WStype_TEXT:
- //if(localTesting) USE_SERIAL.printf("[WSc] get text: %s\n", payload);
-
- payloadDecodeError = deserializeJson(jsonDoc, payload);
- // Test if parsing succeeds.
- if (payloadDecodeError) {
- USE_SERIAL.printf("deserializeJson() failed: \n");
- USE_SERIAL.println(payloadDecodeError.c_str());
- }else{
- //USE_SERIAL.printf("parseObject() succeeded\n");
- JsonObject metrics = jsonDoc["metrics"];
- if (!metrics.isNull()) {
-
- if(localTesting && genRandomVals){
- metrics["v.b.soc"] = random(0,200)/2;
- metrics["v.b.power"] = random(-MAXINPOWER*10,MAXOUTPOWER*10+1)/10;
- metrics["v.b.range.ideal"] = random(360*10,400*10)/10;
- metrics["v.b.range.ideal"] = random(360*10,400*10)/10;
- metrics["v.e.temp"] = random(12*10,17*10)/10;
- metrics["v.b.temp"] = random(18*10,21*10)/10;
- metrics["xkn.b.inlet.temp"] = random(14*10,19*10)/10;
- metrics["v.b.consumption"] = random(130,240);
- }
-
- // v.b.soc
- if(metrics.containsKey("v.b.soc") && metrics["v.b.soc"]!=vbsoc){
- vbsoc = metrics["v.b.soc"];
- //USE_SERIAL.printf("[json] v.b.soc: %f\n", vbsoc);
- }
- if(slowRefreshTrigger) draw_vbsoc(vbsoc);
-
- // v.b.range.ideal
- if(metrics.containsKey("v.b.range.ideal") && metrics["v.b.range.ideal"]!=vbrangeideal){
- vbrangeideal = metrics["v.b.range.ideal"];
- }
- // v.b.range.full
- if(metrics.containsKey("v.b.range.full") && metrics["v.b.range.full"]!=vbrangefull){
- vbrangefull = metrics["v.b.range.full"];
- }
- if(slowRefreshTrigger) draw_vbrange();
-
- // v.e.temp
- if(metrics.containsKey("v.e.temp") && metrics["v.e.temp"]!=vetemp){
- vetemp = metrics["v.e.temp"];
- }
- // v.b.temp
- if(metrics.containsKey("v.b.temp") && metrics["v.b.temp"]!=vbtemp){
- vbtemp = metrics["v.b.temp"];
- }
- // xkn.b.inlet.temp
- if(metrics.containsKey("xkn.b.inlet.temp") && metrics["xkn.b.inlet.temp"]!=xknbinlettemp){
- xknbinlettemp = metrics["xkn.b.inlet.temp"];
- }
- if(mildRefreshTrigger) draw_temps();
-
- // xkn.b.inlet.temp
- if(metrics.containsKey("v.b.consumption") && metrics["v.b.consumption"]!=vbconsumption){
- vbconsumption = metrics["v.b.consumption"];
- }
- if(mildRefreshTrigger) draw_vbconsumption();
-
- // v.b.power
- if(metrics.containsKey("v.b.power")){
- vbpower = metrics["v.b.power"];
- //USE_SERIAL.printf("[json] v.b.power: %f\n", vbpower);
- }
-
- if(fastRefreshTrigger) draw_vbpower(vbpower);
-
- if(metrics.containsKey("m.monotonic")){
- //JsonVariant _mmonotonic=metrics["m.monotonic"];
- //int mmonotonic=_mmonotonic.as<int>();
- int mmonotonic=metrics["m.monotonic"].as<int>();
- if(mmonotonic % 2){
- tickerBox(DARKGREEN);
- }else{
- tickerBox(BLUE);
- }
- }
-
- if(M5.BtnA.wasReleased()) sendButtonA();
- if(M5.BtnB.wasReleased()) sendButtonB();
- if(M5.BtnC.wasReleased()) changeLCDBrightness();
-
- }
-
- if(M5triggerUpdate){
- M5.update();
- M5triggerUpdate = 0;
- }
- if(slowRefreshTrigger){
- slowRefreshTimer=0;
- //USE_SERIAL.printf("slowRefreshTimer reset\n");
- }
- if(mildRefreshTrigger){
- mildRefreshTimer=0;
- //USE_SERIAL.printf("mildRefreshTimer reset\n");
- }
- if(fastRefreshTrigger){
- fastRefreshTimer=0;
- //USE_SERIAL.printf("fastRefreshTimer reset\n");
- }
- }
- // send message to server
- // webSocket.sendTXT("message here");
- break;
- case WStype_BIN:
- USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
- hexdump(payload, length);
-
- // send data to server
- // webSocket.sendBIN(payload, length);
- break;
- case WStype_ERROR:
- case WStype_FRAGMENT_TEXT_START:
- case WStype_FRAGMENT_BIN_START:
- case WStype_FRAGMENT:
- case WStype_FRAGMENT_FIN:
- break;
- }
-
- }
-
- void setup() {
-
- M5.begin();
- M5.Power.begin();
- M5.Lcd.setBrightness(LCDBrightnessSteps[LCDBrightnessStep+1]);
- // USE_SERIAL.begin(921600);
- // USE_SERIAL.begin(115200);
- USE_SERIAL.begin(230400);
-
- //Serial.setDebugOutput(true);
- USE_SERIAL.setDebugOutput(true);
-
- USE_SERIAL.println();
-
- //M5.Lcd.fillScreen(BLACK);
-
- ledcDetachPin(SPEAKER_PIN);
- pinMode(SPEAKER_PIN, INPUT);
-
- for(uint8_t t = 5; t > 0; t--) {
- USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
- USE_SERIAL.flush();
- delay(500);
- }
-
- WiFiMulti.addAP("OVMSWifi", "W1f1P4ssW0rd"); // Change This to your OVMS
-
- USE_SERIAL.printf("[Wifi] Added APs...\n");
-
- WiFi.disconnect();
- if(WiFiMulti.run() != WL_CONNECTED){
- M5.Lcd.fillRect(0, 220, 320, 32, BLUE);
- M5.Lcd.setCursor(6, 222);
- M5.Lcd.setTextColor(WHITE);
- M5.Lcd.setTextSize(2);
- M5.Lcd.print("[Wifi] Connecting...");
- USE_SERIAL.printf("[Wifi] Connecting...\n");
- dummyCounter = 1;
- tickerBox(RED);
- while(WiFiMulti.run() != WL_CONNECTED) {
- USE_SERIAL.printf("[Wifi] Connecting... count %d\n",dummyCounter++);
- M5.Lcd.print(".");
- M5.update();
- delay(500);
- if (M5.BtnC.wasReleased()) changeLCDBrightness();
- }
-
- //hexdump(WiFi.SSID().c_str(), sizeof(WiFi.SSID().c_str()));
- USE_SERIAL.printf("[Wifi] Connected: %s\n",WiFi.SSID().c_str());
-
- M5.Lcd.fillRect(0, 220, 320, 32, BLACK);
- M5.update();
- }
-
-
- // server address, port and URL
- webSocket.begin("192.168.4.1", 80, "/");
-
- // event handler
- webSocket.onEvent(webSocketEvent);
-
- // use HTTP Basic Authorization this is optional remove if not needed
- webSocket.setAuthorization(OVMSUSER, OVMSPASS);
-
- // try ever 5000 again if connection has failed
- webSocket.setReconnectInterval(2000);
-
- }
-
- void loop() {
- webSocket.loop();
- if(WiFiMulti.run() != WL_CONNECTED){
- M5.Lcd.fillRect(0, 220, 320, 32, BLUE);
- M5.Lcd.setCursor(6, 222);
- M5.Lcd.setTextColor(WHITE);
- M5.Lcd.setTextSize(2);
- M5.Lcd.print("[Wifi] Reconnecting...");
- while(WiFiMulti.run() != WL_CONNECTED) {
- USE_SERIAL.printf("[Wifi] Connecting...\n");
- M5.Lcd.print(".");
- M5.update();
- delay(500);
- if (M5.BtnC.wasReleased()) changeLCDBrightness();
- }
-
- USE_SERIAL.printf("Wifi: %s\n",WiFi.SSID().c_str());
-
- M5.Lcd.fillRect(0, 220, 320, 32, BLUE);
- M5.Lcd.setCursor(6, 222);
- M5.Lcd.print("[Wifi] : ");
- M5.Lcd.print(WiFi.SSID().c_str());
- M5.update();
- M5.Speaker.mute();
- delay(500);
- M5.Lcd.fillRect(0, 220, 320, 32, BLACK);
- M5.update();
- }
- //M5.Lcd.fillScreen(BLACK);
- if(M5triggerUpdate){
- M5.update();
- M5triggerUpdate = 0;
- }
- //USE_SERIAL.printf("end of loop\n");
- }
|