Gavin
Published

Wireless Weather Monitor

Use Raspberry Pi RP2040 & WizFi360 to display Weather info through openweather API on the screen(GC9A01)

IntermediateFull instructions provided2,011
Wireless Weather Monitor

Things used in this project

Hardware components

WizFi360-EVB-Pico
WIZnet WizFi360-EVB-Pico
×1
RP2040
Raspberry Pi RP2040
×1
GC9A01 1.28 Inch Round LCD
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

openweather API

Story

Read more

Schematics

Wireless Weather Moniter_Schmatic.pdf

Code

Wireless_Weather_Moniter_Code

Arduino
/*
 WizFi360 example: Wireless Weather Moniter
*/

#include "WizFi360.h"
#include <RingBuf.h>
#include <ArduinoJson.h>

#include <Arduino_GFX_Library.h>
Arduino_GFX *tft = create_default_Arduino_GFX();

#include <PNGdec.h>

PNG png;

RingBuf<uint8_t, 3072> myBuffer;

typedef enum 
{   
  link_weather_server = 0,
  get_weather_data,
  link_icon_server,
  get_weather_icon,
  display_status,
  wait_timeout, 
}STATE_;
STATE_ currentState;

/* Wi-Fi info */
char ssid[] = "wiznet";       // your network SSID (name)
char pass[] = "KUvT5sT1Ph";   // your network password
IPAddress ip;
char weather_server[] = "api.openweathermap.org"; 
char weather_icon_server[] = "openweathermap.org"; 
char weather_appid[] = "226ae23125bbe********cc00025657";

uint8_t data_now;
uint8_t value;  
bool json_start;
String json_String; 
uint16_t dataStart = 0;
uint16_t dataEnd = 0;
String dataStr;

String weather_icon_num;
uint16_t weather_icon_len;
uint8_t weather_icon[4096];

String weather_main;
uint8_t weather_temperature;
uint8_t weather_humidity;
uint8_t weather_wind;
uint8_t weather_temperature_min;
uint8_t weather_temperature_max;
String weather_local;

int status = WL_IDLE_STATUS;  // the Wifi radio's status

// Initialize the Ethernet client object
WiFiClient client;
    
void setup() {
  // initialize serial for debugging  
  Serial.begin(115200);

  tft->begin();
  tft->fillScreen(LIGHTGREY);
  pinMode(22, OUTPUT); 
  digitalWrite(22, HIGH);   
  display_wifi_status();
  // initialize serial for WizFi360 module
  Serial2.setFIFOSize(3072);
  Serial2.begin(2000000);
  WiFi.init(&Serial2);

  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    // don't continue
    while (true);
  }
  
  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }
  display_wifi_status();
//  while (!Serial) {
//    ; // wait for serial port to connect. Needed for native USB port only
//  }  
  // print your WiFi shield's IP address
  ip = WiFi.localIP();

  currentState = link_weather_server;
  display_dashboard();
}

void loop(){
  switch(currentState){
    case link_weather_server:
       {
        // if you get a connection, report back via serial
        if (client.connect(weather_server,80)) {
          Serial.println("Connected to server");
          // Make a HTTP request
          // https://api.openweathermap.org/data/2.5/weather?lat=23.43&lon=114.07&appid=226ae23125bbe4c15af15ecc00025657
          client.println(String("GET /data/2.5/weather?lat=22.428&lon=114.210&appid=") + String(weather_appid) + String(" HTTP/1.1"));
          client.println(String("Host:") + String(weather_server));
          client.println("Connection: close");
          client.println();
          data_now = 0;
        }
        currentState = get_weather_data;
       }
      break;
      
    case get_weather_data:
       {          
          while (client.available()) {
            myBuffer.push(client.read()); 
            data_now =1;
          }          
          if(data_now)
          {
            json_String = "";
            json_start = false;
            while (myBuffer.pop(value)) {
              //Serial.print((char)value);
              if(value == '{')
              {
                json_start = true;
              }
              if(json_start)
              {
                json_String += (char)value;
              }
            }
            dataStart = json_String.indexOf("icon") + strlen("icon") + 3;
            dataEnd = json_String.indexOf("}", dataStart) - 1; 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_icon_num = dataStr;            
       
            dataStart = json_String.indexOf("main") + strlen("main") + 3;
            dataEnd = json_String.indexOf(",", dataStart) - 1; 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_main = dataStr;
            tft->fillRect(35,90,120,20,LIGHTGREY);
            tft->setTextColor(WHITE);
            if(weather_main.length()==4)
            {
              tft->setCursor(40, 90);
            }
            else
            {
              tft->setCursor(37, 90);
            }        
            tft->setTextSize(2);
            tft->println(weather_main);
            
            dataStart = json_String.indexOf("temp") + strlen("temp") + 2;
            dataEnd = json_String.indexOf(".", dataStart); 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_temperature = dataStr.toInt()-272;
            
            dataStart = json_String.indexOf("temp_min") + strlen("temp_min") + 2;
            dataEnd = json_String.indexOf(".", dataStart); 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_temperature_min = dataStr.toInt()-272;
            
            dataStart = json_String.indexOf("temp_max") + strlen("temp_max") + 2;
            dataEnd = json_String.indexOf(".", dataStart); 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_temperature_max = dataStr.toInt()-272;

            tft->drawRoundRect(129,72,64,8,5,LIGHTGREY);
            uint8_t temp_uint8 = (weather_temperature*64)/(100*(weather_temperature_max-weather_temperature_min));
            tft->fillRoundRect(129,72,temp_uint8,8,8,DARKGREY);

            tft->fillRect(125,34,45,30,LIGHTGREY);
            tft->setCursor(125, 34);
            tft->setTextSize(4);
            tft->println(weather_temperature);              

            dataStart = json_String.indexOf("humidity") + strlen("humidity") + 2;
            dataEnd = json_String.indexOf(",", dataStart); 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_humidity = dataStr.toInt();
            tft->fillRect(156,117,20,20,LIGHTGREY);         
            tft->setTextColor(WHITE);
            tft->setTextSize(2);
            tft->setCursor(156, 117);  
            tft->print(weather_humidity);
  
            dataStart = json_String.indexOf("speed") + strlen("speed") + 2;
            dataEnd = json_String.indexOf(",", dataStart)-1; 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_wind = dataStr.toInt();
            tft->fillRect(113,137,30,20,LIGHTGREY);
            tft->setCursor(113, 137);
            tft->print(weather_wind);

            dataStart = json_String.indexOf("name") + strlen("name") + 3;
            dataEnd = json_String.indexOf("\"", dataStart); 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_local = dataStr;
            
            client.stop();
            delay(500);
            data_now = 0;
            
            if(weather_icon_num.length()!=0)
            {
                currentState = link_icon_server;
            }else{
                currentState = link_weather_server;
            }            
          }
       }
      break;

    case link_icon_server:
       {  
           // if you get a connection, report back via serial
          if (client.connect(weather_icon_server,80)) {
            Serial.println("Connected to weather_icon_server");
            // Make a HTTP request
            //https://openweathermap.org/img/wn/10d@4x.png
            //client.println(String("GET /img/wn/10d@2x.png HTTP/1.1"));  //@2x 100px*100px
            client.println(String("GET /img/wn/") + String(weather_icon_num) + String("@2x.png HTTP/1.1"));  //@2x 100px*100px
            //client.println(String("GET /img/wn/") + String(weather_icon_num) + String(".png HTTP/1.1"));
            client.println(String("Host:") + String(weather_icon_server));
            client.println("Connection: close");
            client.println();
            data_now = 0;
        }
        json_String = "";
        currentState = get_weather_icon;
       }
      break;
      
     case get_weather_icon:   {   
          while (client.available()) {
            json_String += (char)client.read();
            data_now =1;            
          }
          if(data_now)
          {
            dataStart = json_String.indexOf("Content-Length: ") + strlen("Content-Length: ");
            dataEnd = json_String.indexOf("\n", dataStart); 
            dataStr = json_String.substring(dataStart, dataEnd);
            weather_icon_len = dataStr.toInt();
            dataStart = json_String.indexOf("Accept-Ranges: bytes")+ strlen("Accept-Ranges: bytes")+4;
            dataStr = json_String.substring(dataStart, json_String.length());
            uint16_t weather_icon_cnt;
            weather_icon_cnt = weather_icon_len + dataStart - json_String.length();
            while(weather_icon_cnt>0)
            {
              while(client.available()){
              dataStr += (char)client.read();
              weather_icon_cnt--;
              }
            }
            client.stop();
            data_now = 0;
            currentState = display_status;
          }
       }
      break;
      
    case display_status:
       {
          int rc = png.openRAM((uint8_t *)dataStr.c_str(), weather_icon_len, PNGDraw);
          if (rc == PNG_SUCCESS) {
            char szTemp[256];
            sprintf(szTemp, "image specs: (%d x %d), %d bpp, pixel type: %d\n", png.getWidth(), png.getHeight(), png.getBpp(), png.getPixelType());
            Serial.print(szTemp);
            rc = png.decode(NULL, 0); // no private structure and skip CRC checking
            png.close();
          } // png opened successfully
          else
          {
            Serial.println("ERROR");
          }
          currentState = wait_timeout;
       }
      break;
    case wait_timeout:
       {
          tft->fillArc(120,120, 118, 120, 0, 360, GREEN);
          for(uint16_t i=0; i<360;i++)
          {
             delay(2000);
             tft->fillArc(120,120, 118, 120, 180, i+180, LIGHTGREY);
             tft->setTextColor(DARKGREY);
             tft->setTextSize(2);
             tft->fillRect(66,167,180,20,LIGHTGREY);  
              if((i%2 ==0))
              {                   
                  tft->setCursor(71, 167);
                  tft->print("Hong Kong");
              }
              else
              {   
                  tft->setCursor(66, 167);
                  tft->print(weather_local);
              }
          }      
          currentState = link_weather_server;
       }
      break;
  }
}

// Function to draw pixels to the display
void PNGDraw(PNGDRAW *pDraw)
{
  uint16_t usPixels[240];
  uint8_t usMask[240];
  // Serial.printf("Draw pos = 0,%d. size = %d x 1\n", pDraw->y, pDraw->iWidth);
  png.getLineAsRGB565(pDraw, usPixels, PNG_RGB565_LITTLE_ENDIAN, 0x00000000);
  png.getAlphaMask(pDraw, usMask, 1);
  tft->draw16bitRGBBitmap(23, 10 + pDraw->y, usPixels, usMask, pDraw->iWidth, 1);
}

void display_wifi_status()
{
  if( status != WL_CONNECTED)
  {
    tft->fillCircle(120,230,3,DARKGREY);
    tft->fillArc(120,230, 5, 7, 225, 315, DARKGREY); 
    tft->fillArc(120,230, 9, 11, 225, 315, DARKGREY); 
    tft->fillArc(120,230, 13, 15, 225, 315, DARKGREY); 
  }
  else
  {
    tft->fillCircle(120,230,3,GREEN);
    tft->fillArc(120,230, 5, 7, 225, 315, GREEN); 
    tft->fillArc(120,230, 9, 11, 225, 315, GREEN); 
    tft->fillArc(120,230, 13, 15, 225, 315, GREEN); 
  }
}

void display_dashboard()
{  
  //tft->fillRect(119,30,2,180,DARKGREY);  
  tft->setCursor(173, 29);
  tft->setTextSize(2);
  tft->println("o");
  tft->setCursor(182, 41);
  tft->setTextSize(3);
  tft->println("C");
  tft->drawRoundRect(125,69,70,14,7,DARKGREY);
  tft->drawRoundRect(126,70,68,12,6,DARKGREY);
  tft->setTextColor(DARKGREY);
  tft->setTextSize(1);
  tft->setCursor(128, 85);  
  tft->print("min     max");
  
  tft->fillRect(30,110,180,2,DARKGREY);
  tft->setTextColor(DARKGREY);
  tft->setTextSize(2);
  tft->setCursor(43, 117);  
  tft->print("humidity:   %");
  tft->setCursor(48, 137);
  tft->print("wind:   km/h");  
  tft->fillRect(30,160,180,2,DARKGREY);   
  tft->setCursor(71, 167);
  tft->print("Hong Kong");
  tft->setCursor(65, 189);
  tft->print(ip);  
  tft->fillArc(120,120, 118, 120, 0, 360, GREEN);
}

Credits

Gavin

Gavin

24 projects • 23 followers
Make it Funny.

Comments