LAN WeatherStation with Web Interface and PHP/MySQL Backend
A weather station with web Interface displaying results and trends over the previous three hours.
Components and supplies
DSD Tech DHT22 AM2302 Temperature and Humidity Sensor
Arduino Mega 2560
Robojax BMP280
Kuman K15 Ethernet Shield W5100
SainSmart LCD Module For Arduino 20 X 4
3.3V-5V 4 Channel Logic Level Converter
Project description
Code
weather.php
php
This is the page which displays the information. Bring it up by typing IP_ADDRESS\weather.php in your browser.
1<?php 2 3$link = mysqli_connect("127.0.0.1", "username", "password", "weatherdata"); 4 5//in the query I want to split the contents of the timestamp field and just take the time portion 6//$query = "SELECT CONCAT(HOUR(timestamp), ':', MINUTE(timestamp)) as dbTime, temperature, pressure, humidity FROM master ORDER BY uid DESC LIMIT 24"; 7$query = "SELECT uid, TIME(timestamp) as dbTime, temperature, pressure, humidity FROM master ORDER BY uid DESC LIMIT 24"; 8 9//query above is executed 10//i'm not doing any error checking' 11$result = mysqli_query($link, $query); 12 13//declare arrays 14//not really necessary 15$timestamps = array(); 16$temperatures = array(); 17$pressure = array(); 18$humidity = array(); 19$pixelHeights = array(); 20$pixelHeightsP = array(); 21 22//18 cols @ 10 min intervals = 3 hrs, indexed from 0 23$columnRange = 17; 24 25//dump the db results into separate arrays so we can use them later 26while ($db = mysqli_fetch_array($result)) 27{ 28 //chop off the seconds portion of the time value 29 $pieces = explode(':', $db['dbTime']); 30 $formattedTime = $pieces[0] . ':' . $pieces[1]; 31 32 $timestampsTime[] = $formattedTime; 33 $temperatures[] = $db['temperature']; 34 $pressure[] = $db['pressure']; 35 $humidity[] = $db['humidity']; 36 $uid[] = $db['uid']; 37} 38 39//find the min and max temps in the range and 40//define the scale of the graph to display 41$mintemp = 50; 42$maxtemp = -50; 43for ($i = 0; $i <= $columnRange; $i++) 44{ 45 if ($mintemp > $temperatures[$i]) 46 { 47 $mintemp = $temperatures[$i]; 48 $minTempTime = $timestampsTime[$i]; 49 } 50 51 if ($maxtemp < $temperatures[$i]) 52 { 53 $maxtemp = $temperatures[$i]; 54 $maxTempTime = $timestampsTime[$i]; 55 } 56} 57 58$rangeHigh = $maxtemp + 1; 59$rangeLow = $mintemp - 1; 60 61//calculate the height for each data point 62//I add 50 to keep all values above zero, the difference between amounts remains the same 63//The bars are then displayed as 10px wide and x% high using a single pixel as a base 64//I got my pixel graphics from this site: 1x1px.me 65for ($i = 0; $i <= $columnRange; $i++) 66{ 67 $currentTemp = ($temperatures[$i] + 50) - ($rangeLow + 50); 68 $pixelHeights[$i] = round($currentTemp / (($rangeHigh + 50) - ($rangeLow + 50)) * 100); 69} 70 71 72//pressure calculations, same as temperature 73$minpress = 150; 74$maxpress = 50; 75for ($i = 0; $i <= $columnRange; $i++) 76{ 77 if ($minpress > $pressure[$i]) 78 { 79 $minpress = $pressure[$i]; 80 $minPressTime = $timestampsTime[$i]; 81 } 82 83 if ($maxpress < $pressure[$i]) 84 { 85 $maxpress = $pressure[$i]; 86 $maxPressTime = $timestampsTime[$i]; 87 } 88} 89 90$rangeHighP = $maxpress + 1; 91$rangeLowP = $minpress - 1; 92 93$pressureChange = $pressure[0] - $pressure[$columnRange]; 94 95for ($i = 0; $i <= $columnRange; $i++) 96{ 97 $currentPressure = $pressure[$i] - $rangeLowP; 98 $pixelHeightsP[$i] = round($currentPressure / ($rangeHighP - $rangeLowP) * 100); 99} 100 101//calculate rates of change for temperature and pressure 102$rateOfChangePressure1 = ($pressure[0] - $pressure[5]); 103$rateOfChangePressure3 = ($pressure[0] - $pressure[$columnRange]) / 3; 104$rateOfChangeTemp1 = ($temperatures[0] - $temperatures[5]); 105 106//determines the rising/falling/equality graphic 107//graphics came from flaticon.com/authors/elegant-themes 108function showArrowGraphic($val) { 109 110 if ($val > 0) 111 { 112 $arrowGraphic = 'up-sign.png'; 113 } 114 elseif ($val < 0) 115 { 116 $arrowGraphic = 'down-arrow-outline.png'; 117 } 118 else 119 { 120 $arrowGraphic = 'up-and-down-arrow.png'; 121 } 122 return $arrowGraphic; 123 124} 125 126 127 128/* 129All calculations are done above so HTML output starts after the closing PHP tag 130From this point on, PHP is interspersed as needed 131*/ 132?> 133 134 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 135 136<html> 137<head> 138<title>LAN WeatherStation v.1</title> 139</head> 140 141<body> 142<h1>LAN WeatherStation v.1</h1> 143<h2>Current conditions:</h2> 144 145<!-- Summary table --> 146 147<table> 148 <tr> 149 <td width='200'><b>Temperature:</b></td><td><?php echo round($temperatures[0], 1); ?> °C</td> 150 </tr> 151 <tr> 152 <td><b>Barometric pressure:</b> </td><td><?php echo round($pressure[0], 2); ?> kPa 153 <img src='<?php echo $arrow = showArrowGraphic($pressureChange); ?>' alt='arrow'></td> 154 </tr> 155 <tr> 156 <td><b>Relative humidity:</b></td><td><?php echo round($humidity[0], 1); ?> %</td> 157 </tr> 158 <tr> 159 <td valign='bottom' height='25'><b>°C rate of change (1 hr)</b></td><td valign='bottom' height='25'><?php echo round($rateOfChangeTemp1, 1); ?> °C/hr 160 <img src='<?php echo $arrow = showArrowGraphic($rateOfChangeTemp1); ?>' alt='arrow'></td> 161 </tr> 162 <tr> 163 <td><b>kPa rate of change (1 hr)</b></td><td><?php echo round($rateOfChangePressure1, 2); ?> kPa/hr 164 <img src='<?php echo $arrow = showArrowGraphic($rateOfChangePressure1); ?>' alt='arrow'></td> 165 </tr> 166 <tr> 167 <td><b>kPa rate of change (3 hrs)</b></td><td><?php echo round($rateOfChangePressure3, 2); ?> kPa/hr 168 <img src='<?php echo $arrow = showArrowGraphic($rateOfChangePressure3); ?>' alt='arrow'></td> 169 </tr> 170 <tr> 171 <td valign='bottom' height='25' colspan='2'>Last updated at <?php echo $timestampsTime[0]; ?></td> 172 </tr> 173</table> 174 175 176<br> 177 178<!-- Temperature trend --> 179 180<table style='border: 1px solid black;'> 181 <tr> 182 <td colspan='20'><b>Temperature trend (past 3 hours)</b></td> 183 </tr> 184 <tr> 185 <td colspan='20'> </td> 186 </tr> 187 <tr> 188 <td width='150'> 189 <b>Current:</b> <?php echo round($temperatures[0], 1); ?> °C <br> 190 <b style='color:red'>High:</b> <?php echo round($maxtemp, 1); ?> °C <br> 191 <b style='color:blue'>Low:</b> <?php echo round($mintemp, 1); ?> °C 192 </td> 193 <!-- add empty column for spacing --> 194 <td width='10'> 195 196 </td> 197 198 <?php 199 200 //Here we loop over the array of temperature values. 201 //The corresponding values for pixelHeights is at the same index in its array so we stretch our single pixel 202 //graphic to be 10px wide and $pixelHeights[x] high 203 //We also determine which column will be high and low for the range and set the colours accordingly 204 for ($i = 0; $i <= $columnRange; $i++) 205 { 206 if ($temperatures[$i] == $maxtemp) 207 { 208 echo "<td valign='bottom'><img src='red.png' height='" . $pixelHeights[$i] . "' width='10' alt='pixel'></td> \ 209"; 210 } 211 elseif ($temperatures[$i] == $mintemp) 212 { 213 echo "<td valign='bottom'><img src='blue.png' height='" . $pixelHeights[$i] . "' width='10' alt='pixel'></td> \ 214"; 215 } 216 else 217 { 218 echo "<td valign='bottom'><img src='black.png' height='" . $pixelHeights[$i] . "' width='10' alt='pixel'></td> \ 219"; 220 } 221 } 222 ?> 223 224 </tr> 225 <tr> 226 <td colspan='2'> </td> 227 <td colspan='9'><img src='up-sign.png' width='12' alt='arrow'> <?php echo $timestampsTime[0]; ?></td> 228 <td colspan='9' align='right'><?php echo $timestampsTime[$columnRange]; ?> <img src='up-sign.png' width='12' alt='arrow'></td> 229 </tr> 230</table> 231 232 233<br> 234 235<!-- Barometric trend --> 236 237<table style='border: 1px solid black;' > 238 <tr> 239 <td colspan='20'><b>Barometric pressure trend (past 3 hours)</b></td> 240 </tr> 241 <tr> 242 <td colspan='20'> </td> 243 </tr> 244 <tr> 245 <td width='150'> 246 <b>Current:</b> <?php echo round($pressure[0], 2); ?> kPa <br> 247 <b style='color:red'>High:</b> <?php echo round($maxpress, 2); ?> kPa <br> 248 <b style='color:blue'>Low:</b> <?php echo round($minpress, 2); ?> kPa 249 </td> 250 <!-- add empty column for spacing --> 251 <td width='10'> 252 253 </td> 254 255 <?php 256 257 //same as for temperature above 258 for ($i = 0; $i <= $columnRange; $i++) 259 { 260 if ($pressure[$i] == $maxpress) 261 { 262 echo "<td valign='bottom'><img src='red.png' height='" . $pixelHeightsP[$i] . "' width='10' alt='pixel'></td> \ 263"; 264 } 265 elseif ($pressure[$i] == $minpress) 266 { 267 echo "<td valign='bottom'><img src='blue.png' height='" . $pixelHeightsP[$i] . "' width='10' alt='pixel'></td> \ 268"; 269 } 270 else 271 { 272 echo "<td valign='bottom'><img src='black.png' height='" . $pixelHeightsP[$i] . "' width='10' alt='pixel'></td> \ 273"; 274 } 275 } 276 ?> 277 278 </tr> 279 <tr> 280 <td colspan='2'> </td> 281 <td colspan='9'><img src='up-sign.png' width='12' alt='arrow'> <?php echo $timestampsTime[0]; ?></td> 282 <td colspan='9' align='right'><?php echo $timestampsTime[$columnRange]; ?> <img src='up-sign.png' width='12' alt='arrow'></td> 283 </tr> 284</table> 285 286</body> 287</html>
processincoming.php
php
This is the script that processes incoming data.
1<?php 2 3//establish a link to the database 4$link = mysqli_connect("127.0.0.1", "username", "password", "weatherdata"); 5 6//grab the values sent in the GET request 7$temp = round($_GET['t'], 1); 8$press = round($_GET['p'], 2); 9$hum = round($_GET['h'], 1); 10 11 12//this is the query string to send to mysql. the now() function will record the system datetime in the timestamp field 13//a sensible person would be sanitizing his or her inputs before doing this 14$query = "INSERT INTO master (timestamp, temperature, pressure, humidity) VALUES (NOW(), '$temp', '$press', '$hum')"; 15 16//execute the query/commit to the db 17$result = mysqli_query($link, $query); 18 19//close the connection 20mysqli_close($link); 21 22?>
WeatherStation_v1_webclient_no_lcd.ino
arduino
Slimmed down version with no LCD output. For smaller memory boards.
1#include <Wire.h> 2#include <dht.h> 3#include "i2c.h" 4#include "i2c_BMP280.h" 5#include <SPI.h> 6#include <Ethernet.h> 7 8dht DHT; 9BMP280 bmp280; 10 11//specify the temp sensor 12#define DHTTYPE DHT22; 13#define DHT22_PIN 6 14 15float currentTemp; 16float currentHumid; 17 18float baroPressure; 19float currentPressure; 20 21//engineeringtoolbox.com/barometers-elevation-compensation-d_1812.html 22float altitudeAdjustment = 1; 23 24//ethernet client vars 25IPAddress server(192,168,1,35); 26IPAddress ip(192, 168, 1, 36); //in case of DHCP failure 27IPAddress myDns(192, 168, 1, 1); 28EthernetClient client; 29 30byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 31String urlString; 32String temperatureToDB; 33String pressureToDB; 34String humidityToDB; 35 36 37 38void setup() { 39 40 Serial.begin(9600); 41 42 //wait for sensors to be ready 43 delay(3000); 44 45 //Check if BMP 280 is ready 46 if (bmp280.initialize()) 47 { 48 Serial.println("Barometer ready"); 49 } 50 else 51 { 52 Serial.println("Barometer error"); 53 } 54 55 //check if DHT22 is ready 56 int chk = DHT.read22(DHT22_PIN); 57 switch (chk) 58 { 59 case DHTLIB_OK: 60 Serial.println("Temp sensor ready"); 61 break; 62 63 case DHTLIB_ERROR_CHECKSUM: 64 Serial.println("Temp checksum error"); 65 break; 66 67 case DHTLIB_ERROR_TIMEOUT: 68 Serial.println("Temp timeout"); 69 break; 70 71 default: 72 Serial.println("Temp sensor error"); 73 break; 74 } 75 76 bmp280.setEnabled(0); 77 bmp280.triggerMeasurement(); 78 79 DHT.read22(DHT22_PIN); 80 81 if (Ethernet.begin(mac) == 0) 82 { 83 Serial.print("Failed to configure Ethernet using DHCP"); 84 // Check for Ethernet hardware present 85 if (Ethernet.hardwareStatus() == EthernetNoHardware) 86 { 87 Serial.println("Ethernet shield not found"); 88 //show failure flag 89 } 90 91 if (Ethernet.linkStatus() == LinkOFF) 92 { 93 Serial.println("Ethernet cable not connected."); 94 } 95 96 // try to congifure using IP address instead of DHCP: 97 Ethernet.begin(mac, ip, myDns); 98 } 99 else 100 { 101 Serial.print("Got IP via DHCP: "); 102 Serial.println(Ethernet.localIP()); 103 } 104 105 //wait for sensors again 106 delay(3000); 107} 108 109void loop() { 110 111 bmp280.triggerMeasurement(); 112 bmp280.getPressure(baroPressure); 113 114 DHT.read22(DHT22_PIN); 115 currentTemp = DHT.temperature; 116 currentHumid = DHT.humidity; 117 118 currentPressure = (baroPressure / 1000) + altitudeAdjustment; //output kPa 119 120 //build the string to send to the server 121 temperatureToDB = currentTemp; 122 pressureToDB = currentPressure; 123 humidityToDB = currentHumid; 124 125 //send the data 126 urlString = "GET /processincoming.php?t=" + temperatureToDB + "&p=" + pressureToDB + "&h=" + humidityToDB + " HTTP/1.1"; 127 sendDataToServer(urlString); 128 129 //wait 10 minutes 130 for (int i = 0; i < 599; i++) 131 { 132 delay (1000); 133 } 134} 135 136void sendDataToServer(String stringToSend) 137{ 138 Serial.println(stringToSend); 139 if (client.connect(server, 80)) 140 { 141 client.println(stringToSend); 142 client.println("Host: 192.168.1.35"); 143 client.println("Connection: close"); 144 client.println(); 145 } 146 else 147 { 148 Serial.println("connection failed"); 149 } 150} 151
processincoming.php
php
This is the script that processes incoming data.
1<?php 2 3//establish a link to the database 4$link = mysqli_connect("127.0.0.1", 5 "username", "password", "weatherdata"); 6 7//grab the values sent in the 8 GET request 9$temp = round($_GET['t'], 1); 10$press = round($_GET['p'], 2); 11$hum 12 = round($_GET['h'], 1); 13 14 15//this is the query string to send to mysql. 16 the now() function will record the system datetime in the timestamp field 17//a 18 sensible person would be sanitizing his or her inputs before doing this 19$query 20 = "INSERT INTO master (timestamp, temperature, pressure, humidity) VALUES (NOW(), 21 '$temp', '$press', '$hum')"; 22 23//execute the query/commit to the db 24$result 25 = mysqli_query($link, $query); 26 27//close the connection 28mysqli_close($link); 29 30?>
WeatherStation_v1_webclient_no_lcd.ino
arduino
Slimmed down version with no LCD output. For smaller memory boards.
1#include <Wire.h> 2#include <dht.h> 3#include "i2c.h" 4#include "i2c_BMP280.h" 5#include <SPI.h> 6#include <Ethernet.h> 7 8dht DHT; 9BMP280 bmp280; 10 11//specify the temp sensor 12#define DHTTYPE DHT22; 13#define DHT22_PIN 6 14 15float currentTemp; 16float currentHumid; 17 18float baroPressure; 19float currentPressure; 20 21//engineeringtoolbox.com/barometers-elevation-compensation-d_1812.html 22float altitudeAdjustment = 1; 23 24//ethernet client vars 25IPAddress server(192,168,1,35); 26IPAddress ip(192, 168, 1, 36); //in case of DHCP failure 27IPAddress myDns(192, 168, 1, 1); 28EthernetClient client; 29 30byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 31String urlString; 32String temperatureToDB; 33String pressureToDB; 34String humidityToDB; 35 36 37 38void setup() { 39 40 Serial.begin(9600); 41 42 //wait for sensors to be ready 43 delay(3000); 44 45 //Check if BMP 280 is ready 46 if (bmp280.initialize()) 47 { 48 Serial.println("Barometer ready"); 49 } 50 else 51 { 52 Serial.println("Barometer error"); 53 } 54 55 //check if DHT22 is ready 56 int chk = DHT.read22(DHT22_PIN); 57 switch (chk) 58 { 59 case DHTLIB_OK: 60 Serial.println("Temp sensor ready"); 61 break; 62 63 case DHTLIB_ERROR_CHECKSUM: 64 Serial.println("Temp checksum error"); 65 break; 66 67 case DHTLIB_ERROR_TIMEOUT: 68 Serial.println("Temp timeout"); 69 break; 70 71 default: 72 Serial.println("Temp sensor error"); 73 break; 74 } 75 76 bmp280.setEnabled(0); 77 bmp280.triggerMeasurement(); 78 79 DHT.read22(DHT22_PIN); 80 81 if (Ethernet.begin(mac) == 0) 82 { 83 Serial.print("Failed to configure Ethernet using DHCP"); 84 // Check for Ethernet hardware present 85 if (Ethernet.hardwareStatus() == EthernetNoHardware) 86 { 87 Serial.println("Ethernet shield not found"); 88 //show failure flag 89 } 90 91 if (Ethernet.linkStatus() == LinkOFF) 92 { 93 Serial.println("Ethernet cable not connected."); 94 } 95 96 // try to congifure using IP address instead of DHCP: 97 Ethernet.begin(mac, ip, myDns); 98 } 99 else 100 { 101 Serial.print("Got IP via DHCP: "); 102 Serial.println(Ethernet.localIP()); 103 } 104 105 //wait for sensors again 106 delay(3000); 107} 108 109void loop() { 110 111 bmp280.triggerMeasurement(); 112 bmp280.getPressure(baroPressure); 113 114 DHT.read22(DHT22_PIN); 115 currentTemp = DHT.temperature; 116 currentHumid = DHT.humidity; 117 118 currentPressure = (baroPressure / 1000) + altitudeAdjustment; //output kPa 119 120 //build the string to send to the server 121 temperatureToDB = currentTemp; 122 pressureToDB = currentPressure; 123 humidityToDB = currentHumid; 124 125 //send the data 126 urlString = "GET /processincoming.php?t=" + temperatureToDB + "&p=" + pressureToDB + "&h=" + humidityToDB + " HTTP/1.1"; 127 sendDataToServer(urlString); 128 129 //wait 10 minutes 130 for (int i = 0; i < 599; i++) 131 { 132 delay (1000); 133 } 134} 135 136void sendDataToServer(String stringToSend) 137{ 138 Serial.println(stringToSend); 139 if (client.connect(server, 80)) 140 { 141 client.println(stringToSend); 142 client.println("Host: 192.168.1.35"); 143 client.println("Connection: close"); 144 client.println(); 145 } 146 else 147 { 148 Serial.println("connection failed"); 149 } 150} 151
weather.php
php
This is the page which displays the information. Bring it up by typing IP_ADDRESS\weather.php in your browser.
1<?php 2 3$link = mysqli_connect("127.0.0.1", "username", "password", "weatherdata"); 4 5//in the query I want to split the contents of the timestamp field and just take the time portion 6//$query = "SELECT CONCAT(HOUR(timestamp), ':', MINUTE(timestamp)) as dbTime, temperature, pressure, humidity FROM master ORDER BY uid DESC LIMIT 24"; 7$query = "SELECT uid, TIME(timestamp) as dbTime, temperature, pressure, humidity FROM master ORDER BY uid DESC LIMIT 24"; 8 9//query above is executed 10//i'm not doing any error checking' 11$result = mysqli_query($link, $query); 12 13//declare arrays 14//not really necessary 15$timestamps = array(); 16$temperatures = array(); 17$pressure = array(); 18$humidity = array(); 19$pixelHeights = array(); 20$pixelHeightsP = array(); 21 22//18 cols @ 10 min intervals = 3 hrs, indexed from 0 23$columnRange = 17; 24 25//dump the db results into separate arrays so we can use them later 26while ($db = mysqli_fetch_array($result)) 27{ 28 //chop off the seconds portion of the time value 29 $pieces = explode(':', $db['dbTime']); 30 $formattedTime = $pieces[0] . ':' . $pieces[1]; 31 32 $timestampsTime[] = $formattedTime; 33 $temperatures[] = $db['temperature']; 34 $pressure[] = $db['pressure']; 35 $humidity[] = $db['humidity']; 36 $uid[] = $db['uid']; 37} 38 39//find the min and max temps in the range and 40//define the scale of the graph to display 41$mintemp = 50; 42$maxtemp = -50; 43for ($i = 0; $i <= $columnRange; $i++) 44{ 45 if ($mintemp > $temperatures[$i]) 46 { 47 $mintemp = $temperatures[$i]; 48 $minTempTime = $timestampsTime[$i]; 49 } 50 51 if ($maxtemp < $temperatures[$i]) 52 { 53 $maxtemp = $temperatures[$i]; 54 $maxTempTime = $timestampsTime[$i]; 55 } 56} 57 58$rangeHigh = $maxtemp + 1; 59$rangeLow = $mintemp - 1; 60 61//calculate the height for each data point 62//I add 50 to keep all values above zero, the difference between amounts remains the same 63//The bars are then displayed as 10px wide and x% high using a single pixel as a base 64//I got my pixel graphics from this site: 1x1px.me 65for ($i = 0; $i <= $columnRange; $i++) 66{ 67 $currentTemp = ($temperatures[$i] + 50) - ($rangeLow + 50); 68 $pixelHeights[$i] = round($currentTemp / (($rangeHigh + 50) - ($rangeLow + 50)) * 100); 69} 70 71 72//pressure calculations, same as temperature 73$minpress = 150; 74$maxpress = 50; 75for ($i = 0; $i <= $columnRange; $i++) 76{ 77 if ($minpress > $pressure[$i]) 78 { 79 $minpress = $pressure[$i]; 80 $minPressTime = $timestampsTime[$i]; 81 } 82 83 if ($maxpress < $pressure[$i]) 84 { 85 $maxpress = $pressure[$i]; 86 $maxPressTime = $timestampsTime[$i]; 87 } 88} 89 90$rangeHighP = $maxpress + 1; 91$rangeLowP = $minpress - 1; 92 93$pressureChange = $pressure[0] - $pressure[$columnRange]; 94 95for ($i = 0; $i <= $columnRange; $i++) 96{ 97 $currentPressure = $pressure[$i] - $rangeLowP; 98 $pixelHeightsP[$i] = round($currentPressure / ($rangeHighP - $rangeLowP) * 100); 99} 100 101//calculate rates of change for temperature and pressure 102$rateOfChangePressure1 = ($pressure[0] - $pressure[5]); 103$rateOfChangePressure3 = ($pressure[0] - $pressure[$columnRange]) / 3; 104$rateOfChangeTemp1 = ($temperatures[0] - $temperatures[5]); 105 106//determines the rising/falling/equality graphic 107//graphics came from flaticon.com/authors/elegant-themes 108function showArrowGraphic($val) { 109 110 if ($val > 0) 111 { 112 $arrowGraphic = 'up-sign.png'; 113 } 114 elseif ($val < 0) 115 { 116 $arrowGraphic = 'down-arrow-outline.png'; 117 } 118 else 119 { 120 $arrowGraphic = 'up-and-down-arrow.png'; 121 } 122 return $arrowGraphic; 123 124} 125 126 127 128/* 129All calculations are done above so HTML output starts after the closing PHP tag 130From this point on, PHP is interspersed as needed 131*/ 132?> 133 134 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 135 136<html> 137<head> 138<title>LAN WeatherStation v.1</title> 139</head> 140 141<body> 142<h1>LAN WeatherStation v.1</h1> 143<h2>Current conditions:</h2> 144 145<!-- Summary table --> 146 147<table> 148 <tr> 149 <td width='200'><b>Temperature:</b></td><td><?php echo round($temperatures[0], 1); ?> °C</td> 150 </tr> 151 <tr> 152 <td><b>Barometric pressure:</b> </td><td><?php echo round($pressure[0], 2); ?> kPa 153 <img src='<?php echo $arrow = showArrowGraphic($pressureChange); ?>' alt='arrow'></td> 154 </tr> 155 <tr> 156 <td><b>Relative humidity:</b></td><td><?php echo round($humidity[0], 1); ?> %</td> 157 </tr> 158 <tr> 159 <td valign='bottom' height='25'><b>°C rate of change (1 hr)</b></td><td valign='bottom' height='25'><?php echo round($rateOfChangeTemp1, 1); ?> °C/hr 160 <img src='<?php echo $arrow = showArrowGraphic($rateOfChangeTemp1); ?>' alt='arrow'></td> 161 </tr> 162 <tr> 163 <td><b>kPa rate of change (1 hr)</b></td><td><?php echo round($rateOfChangePressure1, 2); ?> kPa/hr 164 <img src='<?php echo $arrow = showArrowGraphic($rateOfChangePressure1); ?>' alt='arrow'></td> 165 </tr> 166 <tr> 167 <td><b>kPa rate of change (3 hrs)</b></td><td><?php echo round($rateOfChangePressure3, 2); ?> kPa/hr 168 <img src='<?php echo $arrow = showArrowGraphic($rateOfChangePressure3); ?>' alt='arrow'></td> 169 </tr> 170 <tr> 171 <td valign='bottom' height='25' colspan='2'>Last updated at <?php echo $timestampsTime[0]; ?></td> 172 </tr> 173</table> 174 175 176<br> 177 178<!-- Temperature trend --> 179 180<table style='border: 1px solid black;'> 181 <tr> 182 <td colspan='20'><b>Temperature trend (past 3 hours)</b></td> 183 </tr> 184 <tr> 185 <td colspan='20'> </td> 186 </tr> 187 <tr> 188 <td width='150'> 189 <b>Current:</b> <?php echo round($temperatures[0], 1); ?> °C <br> 190 <b style='color:red'>High:</b> <?php echo round($maxtemp, 1); ?> °C <br> 191 <b style='color:blue'>Low:</b> <?php echo round($mintemp, 1); ?> °C 192 </td> 193 <!-- add empty column for spacing --> 194 <td width='10'> 195 196 </td> 197 198 <?php 199 200 //Here we loop over the array of temperature values. 201 //The corresponding values for pixelHeights is at the same index in its array so we stretch our single pixel 202 //graphic to be 10px wide and $pixelHeights[x] high 203 //We also determine which column will be high and low for the range and set the colours accordingly 204 for ($i = 0; $i <= $columnRange; $i++) 205 { 206 if ($temperatures[$i] == $maxtemp) 207 { 208 echo "<td valign='bottom'><img src='red.png' height='" . $pixelHeights[$i] . "' width='10' alt='pixel'></td> \ 209"; 210 } 211 elseif ($temperatures[$i] == $mintemp) 212 { 213 echo "<td valign='bottom'><img src='blue.png' height='" . $pixelHeights[$i] . "' width='10' alt='pixel'></td> \ 214"; 215 } 216 else 217 { 218 echo "<td valign='bottom'><img src='black.png' height='" . $pixelHeights[$i] . "' width='10' alt='pixel'></td> \ 219"; 220 } 221 } 222 ?> 223 224 </tr> 225 <tr> 226 <td colspan='2'> </td> 227 <td colspan='9'><img src='up-sign.png' width='12' alt='arrow'> <?php echo $timestampsTime[0]; ?></td> 228 <td colspan='9' align='right'><?php echo $timestampsTime[$columnRange]; ?> <img src='up-sign.png' width='12' alt='arrow'></td> 229 </tr> 230</table> 231 232 233<br> 234 235<!-- Barometric trend --> 236 237<table style='border: 1px solid black;' > 238 <tr> 239 <td colspan='20'><b>Barometric pressure trend (past 3 hours)</b></td> 240 </tr> 241 <tr> 242 <td colspan='20'> </td> 243 </tr> 244 <tr> 245 <td width='150'> 246 <b>Current:</b> <?php echo round($pressure[0], 2); ?> kPa <br> 247 <b style='color:red'>High:</b> <?php echo round($maxpress, 2); ?> kPa <br> 248 <b style='color:blue'>Low:</b> <?php echo round($minpress, 2); ?> kPa 249 </td> 250 <!-- add empty column for spacing --> 251 <td width='10'> 252 253 </td> 254 255 <?php 256 257 //same as for temperature above 258 for ($i = 0; $i <= $columnRange; $i++) 259 { 260 if ($pressure[$i] == $maxpress) 261 { 262 echo "<td valign='bottom'><img src='red.png' height='" . $pixelHeightsP[$i] . "' width='10' alt='pixel'></td> \ 263"; 264 } 265 elseif ($pressure[$i] == $minpress) 266 { 267 echo "<td valign='bottom'><img src='blue.png' height='" . $pixelHeightsP[$i] . "' width='10' alt='pixel'></td> \ 268"; 269 } 270 else 271 { 272 echo "<td valign='bottom'><img src='black.png' height='" . $pixelHeightsP[$i] . "' width='10' alt='pixel'></td> \ 273"; 274 } 275 } 276 ?> 277 278 </tr> 279 <tr> 280 <td colspan='2'> </td> 281 <td colspan='9'><img src='up-sign.png' width='12' alt='arrow'> <?php echo $timestampsTime[0]; ?></td> 282 <td colspan='9' align='right'><?php echo $timestampsTime[$columnRange]; ?> <img src='up-sign.png' width='12' alt='arrow'></td> 283 </tr> 284</table> 285 286</body> 287</html>
WeatherStation_20x4_v1_webclient.ino
arduino
Full version with LCD output
1#include <LCD.h> 2#include <LiquidCrystal_I2C.h> 3//#include <Wire.h> 4#include <dht.h> 5#include "i2c.h" 6#include "i2c_BMP280.h" 7#include <SPI.h> 8#include <Ethernet.h> 9 10dht DHT; 11BMP280 bmp280; 12 13//specify the temp sensor 14#define DHTTYPE DHT22; 15#define DHT22_PIN 6 16 17#define I2C_ADDR 0x27 // Define I2C Address where the PCF8574A is 18#define BACKLIGHT_PIN 3 19#define En_pin 2 20#define Rw_pin 1 21#define Rs_pin 0 22#define D4_pin 4 23#define D5_pin 5 24#define D6_pin 6 25#define D7_pin 7 26 27LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin); 28 29//total delay = (lcdDelayScreen1 + lcdDelayScreen2 + lcdDelayScreen3) * loopCount (in seconds) 30int lcdDelayScreen1 = 44; //seconds displaying primary info 31int lcdDelayScreen2 = 8; //seconds displaying secondary info 32int lcdDelayScreen3 = 8; //seconds displaying secondary info 33 34//these all have to match 35int loopCount = 60; //total loops 36float dataPointT[60]; //temperature data points 37float dataPointB[60]; //pressure data points 38 39int mainLoop; //primary loop 40int loopBaroGraph; //secondary loop 41int loopTempGraph; //secondary loop 42 43float currentTemp; 44float currentHumid; 45 46float baroPressure; 47float currentPressure; 48 49float tempDifference = 0; 50float tempValueComparative; 51 52int offset; 53int mt; 54int mp; 55 56float pressDifference = 0; 57float pressValueComparative; 58 59//engineeringtoolbox.com/barometers-elevation-compensation-d_1812.html 60float altitudeAdjustment = 1; 61 62float minTemp; 63float maxTemp; 64float minPressure; 65float maxPressure; 66 67int rangeLowGraph; 68int rangeHighGraph; 69 70float percentOfCol; 71float pixelHeightPercent; 72int pixelHeight; 73 74bool firstLoopComplete = false; 75 76//ethernet client vars 77IPAddress server(192,168,1,35); 78IPAddress ip(192, 168, 1, 250); 79IPAddress myDns(192, 168, 1, 1); 80EthernetClient client; 81byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 82String urlString; 83String temperatureToDB; 84String pressureToDB; 85String humidityToDB; 86 87 88//define characters for temperature indicators 89byte arrowUp[8] = { 90 B00100, 91 B01110, 92 B10101, 93 B00100, 94 B00100, 95 B00100, 96 B00100, 97 B00100, 98}; 99 100byte arrowDown[8] = { 101 B00100, 102 B00100, 103 B00100, 104 B00100, 105 B00100, 106 B10101, 107 B01110, 108 B00100, 109}; 110 111byte equalSign[8] = { 112 B00100, 113 B01110, 114 B10101, 115 B00100, 116 B00100, 117 B10101, 118 B01110, 119 B00100, 120}; 121 122byte row1[8] = { 123 B00000, 124 B00000, 125 B00000, 126 B00000, 127 B00000, 128 B00000, 129 B00000, 130 B11111, 131}; 132 133byte row2[8] = { 134 B00000, 135 B00000, 136 B00000, 137 B00000, 138 B00000, 139 B00000, 140 B11111, 141 B11111, 142}; 143 144byte row3[8] = { 145 B00000, 146 B00000, 147 B00000, 148 B00000, 149 B00000, 150 B11111, 151 B11111, 152 B11111, 153}; 154 155byte row4[8] = { 156 B00000, 157 B00000, 158 B00000, 159 B00000, 160 B11111, 161 B11111, 162 B11111, 163 B11111, 164}; 165 166byte row5[8] = { 167 B00000, 168 B00000, 169 B00000, 170 B11111, 171 B11111, 172 B11111, 173 B11111, 174 B11111, 175}; 176 177byte row6[8] = { 178 B00000, 179 B00000, 180 B11111, 181 B11111, 182 B11111, 183 B11111, 184 B11111, 185 B11111, 186}; 187 188byte row7[8] = { 189 B00000, 190 B11111, 191 B11111, 192 B11111, 193 B11111, 194 B11111, 195 B11111, 196 B11111, 197}; 198 199byte row8[8] = { 200 B11111, 201 B11111, 202 B11111, 203 B11111, 204 B11111, 205 B11111, 206 B11111, 207 B11111, 208}; 209 210void setup() { 211 212 int setupLoop; 213 bool dotPosition = true; 214 215 Serial.begin(9600); 216 217 lcd.begin (20,4); 218 219 //Switch on the backlight 220 lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); 221 lcd.setBacklight(HIGH); 222 lcd.home (); 223 224 //delay a few seconds so the sensors are ready 225 for (setupLoop = 1; setupLoop < 8; setupLoop++) 226 { 227 lcd.clear(); 228 229 if (dotPosition) 230 { 231 lcd.print("Initializing ."); 232 lcd.setCursor(0, 1); 233 lcd.print("WeatherStation v.1"); 234 235 } 236 else 237 { 238 lcd.print("Initializing ."); 239 lcd.setCursor(0, 1); 240 lcd.print("WeatherStation v.1"); 241 } 242 243 dotPosition = !dotPosition; 244 delay(500); 245 } 246 247 //Check if BMP 280 is ready 248 lcd.setCursor(0, 2); 249 if (bmp280.initialize()) 250 { 251 lcd.print("Barometer ready"); 252 } 253 else 254 { 255 lcd.print("Barometer error"); 256 } 257 258 lcd.setCursor(0, 3); 259 260 //check if DHT22 is ready 261 int chk = DHT.read22(DHT22_PIN); 262 switch (chk) 263 { 264 case DHTLIB_OK: 265 lcd.print("Temp sensor ready"); 266 break; 267 268 case DHTLIB_ERROR_CHECKSUM: 269 lcd.print("Temp checksum error"); 270 break; 271 272 case DHTLIB_ERROR_TIMEOUT: 273 lcd.print("Temp timeout"); 274 break; 275 276 default: 277 lcd.print("Temp sensor error"); 278 break; 279 } 280 281 //leave info on screen long enough 282 delay(2000); 283 284 bmp280.setEnabled(0); 285 bmp280.triggerMeasurement(); 286 287 bmp280.awaitMeasurement(); 288 bmp280.getPressure(baroPressure); 289 DHT.read22(DHT22_PIN); 290 291 //populate baseline datapoints with startup values 292 int p; 293 for (p = 0; p <= loopCount - 1; p++) 294 { 295 dataPointT[p] = DHT.temperature; 296 dataPointB[p] = (baroPressure / 1000) + altitudeAdjustment; 297 } 298 299 300 lcd.clear(); 301 if (Ethernet.begin(mac) == 0) 302 { 303 lcd.print("Failed to configure Ethernet using DHCP"); 304 // Check for Ethernet hardware present 305 if (Ethernet.hardwareStatus() == EthernetNoHardware) 306 { 307 lcd.println("Ethernet shield not found"); 308 //show failure flag 309 } 310 311 if (Ethernet.linkStatus() == LinkOFF) 312 { 313 lcd.print("Ethernet cable not connected."); 314 } 315 316 // try to congifure using IP address instead of DHCP: 317 Ethernet.begin(mac, ip, myDns); 318 } 319 else 320 { 321 lcd.print("Got IP via DHCP:"); 322 lcd.setCursor(0, 1); 323 lcd.print(Ethernet.localIP()); 324 } 325 326 //keep display up 327 delay(2000); 328} 329 330void loop() { 331 332 for (mainLoop = 0; mainLoop <= loopCount - 1; mainLoop++) 333 { 334 bmp280.awaitMeasurement(); 335 336 DHT.read22(DHT22_PIN); 337 currentTemp = DHT.temperature; 338 currentHumid = DHT.humidity; 339 340 bmp280.getPressure(baroPressure); 341 bmp280.triggerMeasurement(); 342 currentPressure = (baroPressure / 1000) + altitudeAdjustment; 343 344 //read and store the array value before overwriting it 345 tempValueComparative = dataPointT[mainLoop]; 346 dataPointT[mainLoop] = currentTemp; 347 tempDifference = currentTemp - tempValueComparative; 348 349 pressValueComparative = dataPointB[mainLoop]; 350 dataPointB[mainLoop] = currentPressure; 351 pressDifference = currentPressure - pressValueComparative; 352 353 //create lcd chars defined above 354 lcd.createChar(0, arrowUp); 355 lcd.createChar(1, arrowDown); 356 lcd.createChar(2, equalSign); 357 358 //LCD Output begin 359 lcd.clear(); 360 lcd.print(currentTemp, 1); 361 lcd.print((char)223); 362 lcd.print("C "); 363 364 //determine which trend indicator to display 365 showTrendIndicator(tempDifference); 366 367 lcd.print(" "); 368 369 //then display the temperature diff 370 lcd.print(tempDifference); 371 372 //move to the next line and display humidity 373 lcd.setCursor(0, 1); 374 lcd.print(currentPressure, 1); 375 lcd.print(" kPa "); 376 377 showTrendIndicator(pressDifference); 378 379 lcd.print(" "); 380 381 lcd.print(pressDifference); 382 383 lcd.setCursor(0, 2); 384 lcd.print(currentHumid, 1); 385 lcd.print(" % Rel Hum"); 386 387 lcd.setCursor(0, 3); 388 lcd.print("Data age: "); 389 390 //this ensures the 'data age' value displays the max after the first loop completes 391 if (!firstLoopComplete) 392 { 393 if (mainLoop < (loopCount - 1)) 394 { 395 lcd.print(mainLoop); 396 } 397 else 398 { 399 lcd.print(loopCount); 400 firstLoopComplete = true; 401 } 402 } 403 else 404 { 405 lcd.print(loopCount); 406 } 407 408 lcd.print(" m"); 409 410 //send data to server every 10 minutes 411 if ((mainLoop == 0) || (mainLoop % 10 == 0)) 412 { 413 temperatureToDB = currentTemp; 414 pressureToDB = currentPressure; 415 humidityToDB = currentHumid; 416 urlString = "GET /processincoming.php?t=" + temperatureToDB + "&p=" + pressureToDB + "&h=" + humidityToDB + " HTTP/1.1"; 417 sendDataToServer(urlString); 418 } 419 420 //countdown until next screen 421 screenWaitRight(lcdDelayScreen1); 422 423 //+++++++++++++++Screen 1 End+++++++++++++++ 424 425 426 //+++++++++++++++Screen 2 Start+++++++++++++++ 427 428 //bar chart characters 429 lcd.createChar(0, row1); 430 lcd.createChar(1, row2); 431 lcd.createChar(2, row3); 432 lcd.createChar(3, row4); 433 lcd.createChar(4, row5); 434 lcd.createChar(5, row6); 435 lcd.createChar(6, row7); 436 lcd.createChar(7, row8); 437 438 //initialize to something these will never be 439 minTemp = 50; 440 maxTemp = -50; 441 //find min and max temps 442 for (mt = 0; mt <= loopCount - 1; mt++) 443 { 444 //offset value translates a negative result for 'mainLoop - mt' into the appropriate 445 //value in the array sequence 446 offset = getOffsetValue(mainLoop - mt); 447 if (minTemp > dataPointT[offset]) 448 { 449 minTemp = dataPointT[offset]; 450 } 451 } 452 453 for (mt = 0; mt <= loopCount - 1; mt++) 454 { 455 offset = getOffsetValue(mainLoop - mt); 456 if (maxTemp < dataPointT[offset]) 457 { 458 maxTemp = dataPointT[offset]; 459 } 460 } 461 462 //this sets the min/max range that the graph will show 463 rangeLowGraph = minTemp - 1.5; 464 rangeHighGraph = maxTemp + 1.5; 465 466 lcd.clear(); 467 lcd.setCursor(0, 0); 468 lcd.print((char)223); 469 lcd.print("C "); 470 lcd.setCursor(0, 1); 471 lcd.print("H"); 472 lcd.print(maxTemp, 1); 473 lcd.setCursor(0, 2); 474 lcd.print("L"); 475 lcd.print(minTemp, 1); 476 477 for (loopTempGraph = 0; loopTempGraph <= loopCount - 1; loopTempGraph += 4) 478 { 479 offset = getOffsetValue(mainLoop - loopTempGraph); 480 currentTemp = dataPointT[offset]; 481 //i add 50 so the values never go below zero 482 currentTemp = (currentTemp + 50) - (rangeLowGraph + 50); 483 percentOfCol = currentTemp / ((rangeHighGraph + 50) - (rangeLowGraph + 50)); 484 //32 = total pixels vertical 485 pixelHeightPercent = 32 * percentOfCol; 486 pixelHeight = pixelHeightPercent; 487 showGraphColumn(pixelHeight, loopTempGraph / 4); 488 } 489 490 screenWaitLeft(lcdDelayScreen2); 491 492 //+++++++++++++++Screen 2 End+++++++++++++++ 493 494 495 //+++++++++++++++Screen 3 Start+++++++++++++++ 496 497 //initialize to something these will never be 498 minPressure = 250; 499 maxPressure = 75; 500 //find min and max pressure 501 for (mp = 0; mp <= loopCount - 1; mp++) 502 { 503 offset = getOffsetValue(mainLoop - mp); 504 if (minPressure > dataPointB[offset]) 505 { 506 minPressure = dataPointB[offset]; 507 } 508 } 509 510 for (mp = 0; mp <= loopCount - 1; mp++) 511 { 512 offset = getOffsetValue(mainLoop - mp); 513 if (maxPressure < dataPointB[offset]) 514 { 515 maxPressure = dataPointB[offset]; 516 } 517 } 518 519 lcd.clear(); 520 lcd.setCursor(0, 0); 521 lcd.print("kPa"); 522 lcd.setCursor(0, 1); 523 //lcd.print("H"); //doesn't fit on screen :( 524 lcd.print(maxPressure, 1); 525 lcd.setCursor(0, 2); 526 //lcd.print("L"); //doesn't fit on screen :( 527 lcd.print(minPressure, 1); 528 529 for (loopBaroGraph = 0; loopBaroGraph <= loopCount - 1; loopBaroGraph += 4) 530 { 531 offset = getOffsetValue(mainLoop - loopBaroGraph); 532 currentPressure = dataPointB[offset]; 533 currentPressure = currentPressure - (minPressure - 1.5); 534 percentOfCol = currentPressure / ((maxPressure + 1.5) - (minPressure - 1.5)); 535 pixelHeightPercent = 32 * percentOfCol; 536 pixelHeight = pixelHeightPercent; 537 showGraphColumn(pixelHeight, loopBaroGraph / 4); 538 } 539 540 screenWaitLeft(lcdDelayScreen3); 541 542 } //main for loop end 543} 544 545void sendDataToServer(String stringToSend) 546{ 547 Serial.println(stringToSend); 548 if (client.connect(server, 80)) 549 { 550 client.println(stringToSend); 551 client.println("Host: 192.168.1.35"); 552 client.println("Connection: close"); 553 client.println(); 554 } 555 else 556 { 557 // if you didn't get a connection to the server: 558 Serial.println("connection failed"); 559 } 560} 561 562int getOffsetValue(int z) 563{ 564 if (z < 0) 565 { 566 return z + 60; 567 } 568 else 569 { 570 return z; 571 } 572} 573 574void screenWaitRight(int secondsR) 575{ 576 int a; 577 for (a = secondsR; a >= 0; a--) 578 { 579 lcd.setCursor(18, 3); 580 if(a >= 10) 581 { 582 lcd.print(a); 583 } 584 else 585 { 586 lcd.print(" "); 587 lcd.print(a); 588 } 589 delay(1000); 590 } 591} 592 593void screenWaitLeft(int secondsL) 594{ 595 int b; 596 for (b = secondsL; b >= 0; b--) 597 { 598 lcd.setCursor(0, 3); 599 if(b >= 10) 600 { 601 lcd.print(b); 602 } 603 else 604 { 605 lcd.print(b); 606 lcd.print(" "); 607 } 608 delay(1000); 609 } 610} 611 612 613void showTrendIndicator(float val) 614{ 615 if (val > 0) 616 { 617 lcd.write(byte(0)); 618 } 619 else if (val < 0) 620 { 621 lcd.write(byte(1)); 622 } 623 else 624 { 625 lcd.write(byte(2)); 626 } 627} 628 629 630void showGraphColumn(int pixelHeight, int c) 631{ 632 switch (pixelHeight) 633 { 634 case 1: 635 lcd.setCursor(c + 5, 3); 636 lcd.write(byte(0)); 637 break; 638 639 case 2: 640 lcd.setCursor(c + 5, 3); 641 lcd.write(byte(1)); 642 break; 643 644 case 3: 645 lcd.setCursor(c + 5, 3); 646 lcd.write(byte(2)); 647 break; 648 649 case 4: 650 lcd.setCursor(c + 5, 3); 651 lcd.write(byte(3)); 652 break; 653 654 case 5: 655 lcd.setCursor(c + 5, 3); 656 lcd.write(byte(4)); 657 break; 658 659 case 6: 660 lcd.setCursor(c + 5, 3); 661 lcd.write(byte(5)); 662 break; 663 664 case 7: 665 lcd.setCursor(c + 5, 3); 666 lcd.write(byte(6)); 667 break; 668 669 case 8: 670 lcd.setCursor(c + 5, 3); 671 lcd.write(byte(7)); 672 break; 673 674 case 9: 675 lcd.setCursor(c + 5, 3); 676 lcd.write(byte(7)); 677 678 lcd.setCursor(c + 5, 2); 679 lcd.write(byte(0)); 680 break; 681 682 case 10: 683 lcd.setCursor(c + 5, 3); 684 lcd.write(byte(7)); 685 686 lcd.setCursor(c + 5, 2); 687 lcd.write(byte(1)); 688 break; 689 690 case 11: 691 lcd.setCursor(c + 5, 3); 692 lcd.write(byte(7)); 693 694 lcd.setCursor(c + 5, 2); 695 lcd.write(byte(2)); 696 break; 697 698 case 12: 699 lcd.setCursor(c + 5, 3); 700 lcd.write(byte(7)); 701 702 lcd.setCursor(c + 5, 2); 703 lcd.write(byte(3)); 704 break; 705 706 case 13: 707 lcd.setCursor(c + 5, 3); 708 lcd.write(byte(7)); 709 710 lcd.setCursor(c + 5, 2); 711 lcd.write(byte(4)); 712 break; 713 714 case 14: 715 lcd.setCursor(c + 5, 3); 716 lcd.write(byte(7)); 717 718 lcd.setCursor(c + 5, 2); 719 lcd.write(byte(5)); 720 break; 721 722 case 15: 723 lcd.setCursor(c + 5, 3); 724 lcd.write(byte(7)); 725 726 lcd.setCursor(c + 5, 2); 727 lcd.write(byte(6)); 728 break; 729 730 case 16: 731 lcd.setCursor(c + 5, 3); 732 lcd.write(byte(7)); 733 734 lcd.setCursor(c + 5, 2); 735 lcd.write(byte(7)); 736 break; 737 738 case 17: 739 lcd.setCursor(c + 5, 3); 740 lcd.write(byte(7)); 741 742 lcd.setCursor(c + 5, 2); 743 lcd.write(byte(7)); 744 745 lcd.setCursor(c + 5, 1); 746 lcd.write(byte(0)); 747 break; 748 749 case 18: 750 lcd.setCursor(c + 5, 3); 751 lcd.write(byte(7)); 752 753 lcd.setCursor(c + 5, 2); 754 lcd.write(byte(7)); 755 756 lcd.setCursor(c + 5, 1); 757 lcd.write(byte(1)); 758 break; 759 760 case 19: 761 lcd.setCursor(c + 5, 3); 762 lcd.write(byte(7)); 763 764 lcd.setCursor(c + 5, 2); 765 lcd.write(byte(7)); 766 767 lcd.setCursor(c + 5, 1); 768 lcd.write(byte(2)); 769 break; 770 771 case 20: 772 lcd.setCursor(c + 5, 3); 773 lcd.write(byte(7)); 774 775 lcd.setCursor(c + 5, 2); 776 lcd.write(byte(7)); 777 778 lcd.setCursor(c + 5, 1); 779 lcd.write(byte(3)); 780 break; 781 782 case 21: 783 lcd.setCursor(c + 5, 3); 784 lcd.write(byte(7)); 785 786 lcd.setCursor(c + 5, 2); 787 lcd.write(byte(7)); 788 789 lcd.setCursor(c + 5, 1); 790 lcd.write(byte(4)); 791 break; 792 793 case 22: 794 lcd.setCursor(c + 5, 3); 795 lcd.write(byte(7)); 796 797 lcd.setCursor(c + 5, 2); 798 lcd.write(byte(7)); 799 800 lcd.setCursor(c + 5, 1); 801 lcd.write(byte(5)); 802 break; 803 804 case 23: 805 lcd.setCursor(c + 5, 3); 806 lcd.write(byte(7)); 807 808 lcd.setCursor(c + 5, 2); 809 lcd.write(byte(7)); 810 811 lcd.setCursor(c + 5, 1); 812 lcd.write(byte(6)); 813 break; 814 815 case 24: 816 lcd.setCursor(c + 5, 3); 817 lcd.write(byte(7)); 818 819 lcd.setCursor(c + 5, 2); 820 lcd.write(byte(7)); 821 822 lcd.setCursor(c + 5, 1); 823 lcd.write(byte(7)); 824 break; 825 826 case 25: 827 lcd.setCursor(c + 5, 3); 828 lcd.write(byte(7)); 829 830 lcd.setCursor(c + 5, 2); 831 lcd.write(byte(7)); 832 833 lcd.setCursor(c + 5, 1); 834 lcd.write(byte(7)); 835 836 lcd.setCursor(c + 5, 0); 837 lcd.write(byte(0)); 838 break; 839 840 case 26: 841 lcd.setCursor(c + 5, 3); 842 lcd.write(byte(7)); 843 844 lcd.setCursor(c + 5, 2); 845 lcd.write(byte(7)); 846 847 lcd.setCursor(c + 5, 1); 848 lcd.write(byte(7)); 849 850 lcd.setCursor(c + 5, 0); 851 lcd.write(byte(1)); 852 break; 853 854 case 27: 855 lcd.setCursor(c + 5, 3); 856 lcd.write(byte(7)); 857 858 lcd.setCursor(c + 5, 2); 859 lcd.write(byte(7)); 860 861 lcd.setCursor(c + 5, 1); 862 lcd.write(byte(7)); 863 864 lcd.setCursor(c + 5, 0); 865 lcd.write(byte(2)); 866 break; 867 868 case 28: 869 lcd.setCursor(c + 5, 3); 870 lcd.write(byte(7)); 871 872 lcd.setCursor(c + 5, 2); 873 lcd.write(byte(7)); 874 875 lcd.setCursor(c + 5, 1); 876 lcd.write(byte(7)); 877 878 lcd.setCursor(c + 5, 0); 879 lcd.write(byte(3)); 880 break; 881 882 case 29: 883 lcd.setCursor(c + 5, 3); 884 lcd.write(byte(7)); 885 886 lcd.setCursor(c + 5, 2); 887 lcd.write(byte(7)); 888 889 lcd.setCursor(c + 5, 1); 890 lcd.write(byte(7)); 891 892 lcd.setCursor(c + 5, 0); 893 lcd.write(byte(4)); 894 break; 895 896 case 30: 897 lcd.setCursor(c + 5, 3); 898 lcd.write(byte(7)); 899 900 lcd.setCursor(c + 5, 2); 901 lcd.write(byte(7)); 902 903 lcd.setCursor(c + 5, 1); 904 lcd.write(byte(7)); 905 906 lcd.setCursor(c + 5, 0); 907 lcd.write(byte(5)); 908 break; 909 910 case 31: 911 lcd.setCursor(c + 5, 3); 912 lcd.write(byte(7)); 913 914 lcd.setCursor(c + 5, 2); 915 lcd.write(byte(7)); 916 917 lcd.setCursor(c + 5, 1); 918 lcd.write(byte(7)); 919 920 lcd.setCursor(c + 5, 0); 921 lcd.write(byte(6)); 922 break; 923 924 case 32: 925 lcd.setCursor(c + 5, 3); 926 lcd.write(byte(7)); 927 928 lcd.setCursor(c + 5, 2); 929 lcd.write(byte(7)); 930 931 lcd.setCursor(c + 5, 1); 932 lcd.write(byte(7)); 933 934 lcd.setCursor(c + 5, 0); 935 lcd.write(byte(7)); 936 break; 937 } 938} 939
Downloadable files
Weather Station v1
Weather Station v1
Weather Station v1
Weather Station v1
Comments
Only logged in users can leave comments