simple weather app that uses sensor and forecast data from opeanweather.org . The results are shown on TFT and published on Thingspeak. (there may be some of my charts at https://thingspeak.com/channels/26357) This was built to show using k64F ethernet capabilities for K64F roadtest at http://www.element14.com/community/groups/roadtest (there will be a write there shortly)
Dependencies: DHT EthernetInterface HTTPClient NTPClient SDFileSystem SPI_TFT_ILI9341 TFT_fonts mbed-rtos mbed picojson
main.cpp@0:9ab281898a9b, 2015-03-20 (annotated)
- Committer:
- colinmeikle
- Date:
- Fri Mar 20 14:24:06 2015 +0000
- Revision:
- 0:9ab281898a9b
this is a simple weather app that displays the weather on TFT and publishes results on thingspeak. This was built for K64F roadtest http://www.element14.com/community/groups/roadtest
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
colinmeikle | 0:9ab281898a9b | 1 | #include "mbed.h" |
colinmeikle | 0:9ab281898a9b | 2 | #include "SPI_TFT_ILI9341.h" |
colinmeikle | 0:9ab281898a9b | 3 | #include "sansSerif19x20.h" |
colinmeikle | 0:9ab281898a9b | 4 | #include "DHT.h" |
colinmeikle | 0:9ab281898a9b | 5 | #include "EthernetInterface.h" |
colinmeikle | 0:9ab281898a9b | 6 | #include "NTPClient.h" |
colinmeikle | 0:9ab281898a9b | 7 | #include "HTTPClient.h" |
colinmeikle | 0:9ab281898a9b | 8 | #include "picojson.h" |
colinmeikle | 0:9ab281898a9b | 9 | #include "SDFileSystem.h" |
colinmeikle | 0:9ab281898a9b | 10 | //IMPORTANT YOU NEED TO SET THE API KEY for thingspeak look for "your key here" |
colinmeikle | 0:9ab281898a9b | 11 | //TAKE CARE URL doesn't excced buffer size |
colinmeikle | 0:9ab281898a9b | 12 | //sd card |
colinmeikle | 0:9ab281898a9b | 13 | SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCLK, SSEL |
colinmeikle | 0:9ab281898a9b | 14 | //Ethernet Interface |
colinmeikle | 0:9ab281898a9b | 15 | EthernetInterface eth; |
colinmeikle | 0:9ab281898a9b | 16 | //NTP service for date and Time used to set boards RTC |
colinmeikle | 0:9ab281898a9b | 17 | NTPClient ntp; |
colinmeikle | 0:9ab281898a9b | 18 | //HTTP Client for interfacing to web services |
colinmeikle | 0:9ab281898a9b | 19 | HTTPClient http; |
colinmeikle | 0:9ab281898a9b | 20 | char resp[1024]; //buffer for the responce |
colinmeikle | 0:9ab281898a9b | 21 | //On board LED |
colinmeikle | 0:9ab281898a9b | 22 | DigitalOut myled(LED_GREEN); |
colinmeikle | 0:9ab281898a9b | 23 | //serial over USB for debug and Info |
colinmeikle | 0:9ab281898a9b | 24 | Serial pc(USBTX, USBRX); |
colinmeikle | 0:9ab281898a9b | 25 | //temperature sensor |
colinmeikle | 0:9ab281898a9b | 26 | DHT sensor(PTB18,DHT22); // there are several libraries available, this reports CRC error sometimes |
colinmeikle | 0:9ab281898a9b | 27 | //320x240 Display ILI9341 controller (look on ebay) |
colinmeikle | 0:9ab281898a9b | 28 | SPI_TFT_ILI9341 TFT(PTD2, PTD3, PTD1,PTC3 ,PTC4 ,PTD0 ,"TFT"); // mosi, miso, sclk, cs, reset, dc |
colinmeikle | 0:9ab281898a9b | 29 | |
colinmeikle | 0:9ab281898a9b | 30 | int main() |
colinmeikle | 0:9ab281898a9b | 31 | { |
colinmeikle | 0:9ab281898a9b | 32 | int cnt = 0; |
colinmeikle | 0:9ab281898a9b | 33 | int err; |
colinmeikle | 0:9ab281898a9b | 34 | int ret=0; |
colinmeikle | 0:9ab281898a9b | 35 | char val[4][16]; |
colinmeikle | 0:9ab281898a9b | 36 | //used to parse the json data |
colinmeikle | 0:9ab281898a9b | 37 | picojson::value v; |
colinmeikle | 0:9ab281898a9b | 38 | char * json; |
colinmeikle | 0:9ab281898a9b | 39 | HTTPMap map; |
colinmeikle | 0:9ab281898a9b | 40 | HTTPText inText(resp, 1024); |
colinmeikle | 0:9ab281898a9b | 41 | char sdfile[32]; |
colinmeikle | 0:9ab281898a9b | 42 | FILE *fp; |
colinmeikle | 0:9ab281898a9b | 43 | pc.printf("Weather Reporter\n"); |
colinmeikle | 0:9ab281898a9b | 44 | |
colinmeikle | 0:9ab281898a9b | 45 | |
colinmeikle | 0:9ab281898a9b | 46 | //eithernet init |
colinmeikle | 0:9ab281898a9b | 47 | eth.init(); //Use DHCP |
colinmeikle | 0:9ab281898a9b | 48 | ret= eth.connect(); |
colinmeikle | 0:9ab281898a9b | 49 | if (!ret) { |
colinmeikle | 0:9ab281898a9b | 50 | pc.printf("Connected, IP: %s, MASK: %s, GW: %s\n", |
colinmeikle | 0:9ab281898a9b | 51 | eth.getIPAddress(), eth.getNetworkMask(), eth.getGateway()); |
colinmeikle | 0:9ab281898a9b | 52 | } else { |
colinmeikle | 0:9ab281898a9b | 53 | pc.printf("Error eth.connect() - ret = %d\n", ret); |
colinmeikle | 0:9ab281898a9b | 54 | } |
colinmeikle | 0:9ab281898a9b | 55 | |
colinmeikle | 0:9ab281898a9b | 56 | |
colinmeikle | 0:9ab281898a9b | 57 | //setup the TFT DISPLAY |
colinmeikle | 0:9ab281898a9b | 58 | TFT.claim(stdout); // send stdout to the TFT display |
colinmeikle | 0:9ab281898a9b | 59 | //ensure the output is write and not buffered |
colinmeikle | 0:9ab281898a9b | 60 | setvbuf ( stdout , NULL , _IONBF , NULL ); |
colinmeikle | 0:9ab281898a9b | 61 | //TFT.claim(stderr); // send stderr to the TFT display |
colinmeikle | 0:9ab281898a9b | 62 | TFT.set_orientation(1); |
colinmeikle | 0:9ab281898a9b | 63 | TFT.background(Black); // set background to black |
colinmeikle | 0:9ab281898a9b | 64 | //centerx = TFT.width() >> 1; |
colinmeikle | 0:9ab281898a9b | 65 | //centery = TFT.height() >> 1; |
colinmeikle | 0:9ab281898a9b | 66 | |
colinmeikle | 0:9ab281898a9b | 67 | |
colinmeikle | 0:9ab281898a9b | 68 | TFT.cls(); |
colinmeikle | 0:9ab281898a9b | 69 | TFT.locate(0,0); |
colinmeikle | 0:9ab281898a9b | 70 | TFT.set_font((unsigned char*) sansserif); |
colinmeikle | 0:9ab281898a9b | 71 | //printf will now for to TFT because of the TFT.claim(stdout) |
colinmeikle | 0:9ab281898a9b | 72 | printf("Weather Test\n"); |
colinmeikle | 0:9ab281898a9b | 73 | //setup the RTC with date and time |
colinmeikle | 0:9ab281898a9b | 74 | printf("Trying to update time...\r\n"); |
colinmeikle | 0:9ab281898a9b | 75 | time_t ctTime; |
colinmeikle | 0:9ab281898a9b | 76 | NTPResult result; |
colinmeikle | 0:9ab281898a9b | 77 | result = ntp.setTime("pool.ntp.org"); |
colinmeikle | 0:9ab281898a9b | 78 | if (result == NTP_OK) { |
colinmeikle | 0:9ab281898a9b | 79 | time(&ctTime); |
colinmeikle | 0:9ab281898a9b | 80 | printf("Time is set to (UTC):\n%s\n", ctime(&ctTime)); |
colinmeikle | 0:9ab281898a9b | 81 | strcpy(sdfile,"/sd/results/default_results"); //could use time in name |
colinmeikle | 0:9ab281898a9b | 82 | }else{ |
colinmeikle | 0:9ab281898a9b | 83 | printf("Error setting Time\n"); |
colinmeikle | 0:9ab281898a9b | 84 | strcpy(sdfile,"/sd/results/default_results"); |
colinmeikle | 0:9ab281898a9b | 85 | } |
colinmeikle | 0:9ab281898a9b | 86 | |
colinmeikle | 0:9ab281898a9b | 87 | //write to sdcard, we could use the time and date in the filename defained above to give a new file for every session |
colinmeikle | 0:9ab281898a9b | 88 | mkdir("/sd/results", 0777); |
colinmeikle | 0:9ab281898a9b | 89 | fp = fopen(sdfile, "w"); |
colinmeikle | 0:9ab281898a9b | 90 | if (fp == NULL) { |
colinmeikle | 0:9ab281898a9b | 91 | pc.printf("Unable to write the file \n"); |
colinmeikle | 0:9ab281898a9b | 92 | } else { |
colinmeikle | 0:9ab281898a9b | 93 | pc.printf("Writing data to SDCARD \n"); |
colinmeikle | 0:9ab281898a9b | 94 | //time,temp,humidity,forcast,pressure |
colinmeikle | 0:9ab281898a9b | 95 | fprintf(fp, "time,temperature,humidity,forcastTemp,forcastPressure\n"); |
colinmeikle | 0:9ab281898a9b | 96 | fclose(fp); |
colinmeikle | 0:9ab281898a9b | 97 | } |
colinmeikle | 0:9ab281898a9b | 98 | |
colinmeikle | 0:9ab281898a9b | 99 | float humidity=0; |
colinmeikle | 0:9ab281898a9b | 100 | float temperature=-100; |
colinmeikle | 0:9ab281898a9b | 101 | float forcastTemp=0; |
colinmeikle | 0:9ab281898a9b | 102 | float forcastPressure; |
colinmeikle | 0:9ab281898a9b | 103 | wait(10); |
colinmeikle | 0:9ab281898a9b | 104 | pc.printf("\r\nDHT Test program"); |
colinmeikle | 0:9ab281898a9b | 105 | pc.printf("\r\n******************\r\n"); |
colinmeikle | 0:9ab281898a9b | 106 | wait(1); // wait 1 second for device stable status |
colinmeikle | 0:9ab281898a9b | 107 | while(1){ |
colinmeikle | 0:9ab281898a9b | 108 | |
colinmeikle | 0:9ab281898a9b | 109 | //GET forcast data |
colinmeikle | 0:9ab281898a9b | 110 | pc.printf("\nTrying to fetch page...\n"); |
colinmeikle | 0:9ab281898a9b | 111 | //try getting the weather, 5 second timeout |
colinmeikle | 0:9ab281898a9b | 112 | ret = http.get("http://api.openweathermap.org/data/2.5/weather?q=Strathaven,uk", resp, 5000); |
colinmeikle | 0:9ab281898a9b | 113 | if(!ret){ |
colinmeikle | 0:9ab281898a9b | 114 | pc.printf("responce=%s",resp); |
colinmeikle | 0:9ab281898a9b | 115 | json=&resp[0]; |
colinmeikle | 0:9ab281898a9b | 116 | pc.printf("parsing"); |
colinmeikle | 0:9ab281898a9b | 117 | string err = picojson::parse(v, json, json + strlen(json)); |
colinmeikle | 0:9ab281898a9b | 118 | if(err.empty()){ |
colinmeikle | 0:9ab281898a9b | 119 | forcastTemp=v.get("main").get("temp").get<double>(); |
colinmeikle | 0:9ab281898a9b | 120 | forcastTemp=forcastTemp-273.15; |
colinmeikle | 0:9ab281898a9b | 121 | forcastPressure=v.get("main").get("pressure").get<double>(); |
colinmeikle | 0:9ab281898a9b | 122 | // printf("Forcast temp: %f\n", forcastTemp); |
colinmeikle | 0:9ab281898a9b | 123 | } |
colinmeikle | 0:9ab281898a9b | 124 | else{ |
colinmeikle | 0:9ab281898a9b | 125 | pc.printf("error parsing"); |
colinmeikle | 0:9ab281898a9b | 126 | } |
colinmeikle | 0:9ab281898a9b | 127 | } |
colinmeikle | 0:9ab281898a9b | 128 | else{ |
colinmeikle | 0:9ab281898a9b | 129 | pc.printf("ERROR=%d", ret); |
colinmeikle | 0:9ab281898a9b | 130 | } |
colinmeikle | 0:9ab281898a9b | 131 | |
colinmeikle | 0:9ab281898a9b | 132 | err = sensor.readData(); |
colinmeikle | 0:9ab281898a9b | 133 | if (err == 0) { |
colinmeikle | 0:9ab281898a9b | 134 | TFT.cls(); |
colinmeikle | 0:9ab281898a9b | 135 | TFT.locate(0,0); |
colinmeikle | 0:9ab281898a9b | 136 | time(&ctTime); |
colinmeikle | 0:9ab281898a9b | 137 | printf("%s\n", ctime(&ctTime)); |
colinmeikle | 0:9ab281898a9b | 138 | temperature=sensor.ReadTemperature(CELCIUS); |
colinmeikle | 0:9ab281898a9b | 139 | humidity=sensor.ReadHumidity(); |
colinmeikle | 0:9ab281898a9b | 140 | printf("Temperature: %4.2f C \r\n",temperature); |
colinmeikle | 0:9ab281898a9b | 141 | printf("Forcast Temp: %4.2f C \r\n",forcastTemp); |
colinmeikle | 0:9ab281898a9b | 142 | printf("Temperature is %4.2f F \r\n",sensor.ReadTemperature(FARENHEIT)); |
colinmeikle | 0:9ab281898a9b | 143 | printf("Humidity is %4.2f \r\n",humidity); |
colinmeikle | 0:9ab281898a9b | 144 | printf("Dew point is %4.2f \r\n",sensor.CalcdewPoint(sensor.ReadTemperature(CELCIUS), sensor.ReadHumidity())); |
colinmeikle | 0:9ab281898a9b | 145 | printf("Forcast Pressure: %4.2f C \r\n",forcastPressure); |
colinmeikle | 0:9ab281898a9b | 146 | myled = 1; |
colinmeikle | 0:9ab281898a9b | 147 | } else{ |
colinmeikle | 0:9ab281898a9b | 148 | pc.printf("\r\nErr %i \n",err); |
colinmeikle | 0:9ab281898a9b | 149 | myled = 0; |
colinmeikle | 0:9ab281898a9b | 150 | } |
colinmeikle | 0:9ab281898a9b | 151 | |
colinmeikle | 0:9ab281898a9b | 152 | |
colinmeikle | 0:9ab281898a9b | 153 | //sent to thingsspeak |
colinmeikle | 0:9ab281898a9b | 154 | if(cnt==10){ //don't update as often |
colinmeikle | 0:9ab281898a9b | 155 | cnt=0; |
colinmeikle | 0:9ab281898a9b | 156 | memset(resp, '\0', sizeof(resp)); |
colinmeikle | 0:9ab281898a9b | 157 | //POST data |
colinmeikle | 0:9ab281898a9b | 158 | if(temperature!=-100){ //just check we have a valid temp |
colinmeikle | 0:9ab281898a9b | 159 | map.put("api_key","YOUR KEY HERE"); |
colinmeikle | 0:9ab281898a9b | 160 | sprintf(val[0],"%4.1f",temperature); |
colinmeikle | 0:9ab281898a9b | 161 | map.put("field1", val[0]); |
colinmeikle | 0:9ab281898a9b | 162 | sprintf(val[1],"%4.1f",humidity); |
colinmeikle | 0:9ab281898a9b | 163 | map.put("field2", val[1]); |
colinmeikle | 0:9ab281898a9b | 164 | sprintf(val[2],"%4.1f",forcastTemp); |
colinmeikle | 0:9ab281898a9b | 165 | map.put("field3", val[2]); |
colinmeikle | 0:9ab281898a9b | 166 | sprintf(val[3],"%4.1f",forcastPressure); |
colinmeikle | 0:9ab281898a9b | 167 | map.put("field4", val[3]); |
colinmeikle | 0:9ab281898a9b | 168 | pc.printf("\nTrying to post data...\n"); |
colinmeikle | 0:9ab281898a9b | 169 | ret = http.post("https://api.thingspeak.com/update", map, &inText); |
colinmeikle | 0:9ab281898a9b | 170 | if (!ret) |
colinmeikle | 0:9ab281898a9b | 171 | { |
colinmeikle | 0:9ab281898a9b | 172 | pc.printf("Executed POST successfully - read %d characters\n", strlen(resp)); |
colinmeikle | 0:9ab281898a9b | 173 | pc.printf("Result: %s\n", resp); |
colinmeikle | 0:9ab281898a9b | 174 | } |
colinmeikle | 0:9ab281898a9b | 175 | else |
colinmeikle | 0:9ab281898a9b | 176 | { |
colinmeikle | 0:9ab281898a9b | 177 | pc.printf("Error - ret = %d - HTTP return code = %d\n", ret, http.getHTTPResponseCode()); |
colinmeikle | 0:9ab281898a9b | 178 | } |
colinmeikle | 0:9ab281898a9b | 179 | //Write Data to SDCARD |
colinmeikle | 0:9ab281898a9b | 180 | fp = fopen(sdfile, "a"); |
colinmeikle | 0:9ab281898a9b | 181 | if (fp == NULL) { |
colinmeikle | 0:9ab281898a9b | 182 | pc.printf("Unable to write the file \n"); |
colinmeikle | 0:9ab281898a9b | 183 | } else { |
colinmeikle | 0:9ab281898a9b | 184 | pc.printf("Writing data to SDCARD \n"); |
colinmeikle | 0:9ab281898a9b | 185 | //time,temp,humidity,forcast,pressure |
colinmeikle | 0:9ab281898a9b | 186 | fprintf(fp, "%s,%4.1f,%4.1f,%4.1f,%4.1f\n", ctime(&ctTime),temperature,humidity,forcastTemp,forcastPressure); |
colinmeikle | 0:9ab281898a9b | 187 | fclose(fp); |
colinmeikle | 0:9ab281898a9b | 188 | } |
colinmeikle | 0:9ab281898a9b | 189 | } |
colinmeikle | 0:9ab281898a9b | 190 | |
colinmeikle | 0:9ab281898a9b | 191 | } |
colinmeikle | 0:9ab281898a9b | 192 | |
colinmeikle | 0:9ab281898a9b | 193 | cnt++; |
colinmeikle | 0:9ab281898a9b | 194 | wait_ms(6000); |
colinmeikle | 0:9ab281898a9b | 195 | } |
colinmeikle | 0:9ab281898a9b | 196 | } |