├── .gitignore ├── Minimal (v0.1) ├── android │ └── WeatherStation │ │ ├── .idea │ │ ├── .name │ │ ├── copyright │ │ │ └── profiles_settings.xml │ │ ├── encodings.xml │ │ ├── modules.xml │ │ ├── compiler.xml │ │ ├── misc.xml │ │ └── workspace.xml │ │ ├── res │ │ ├── values │ │ │ └── strings.xml │ │ ├── drawable-hdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-ldpi │ │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ │ └── ic_launcher.png │ │ └── layout │ │ │ └── main.xml │ │ ├── gen │ │ └── com │ │ │ └── droid │ │ │ └── ws │ │ │ ├── R.java │ │ │ ├── Manifest.java │ │ │ └── BuildConfig.java │ │ ├── WeatherStation.iml │ │ ├── ant.properties │ │ ├── AndroidManifest.xml │ │ ├── build.xml │ │ └── src │ │ └── com │ │ └── droid │ │ └── ws │ │ └── MainActivity.java ├── documents │ ├── WeatherStation.fzz │ └── media │ │ ├── full_schematic.png │ │ ├── android_full_screen.png │ │ └── power_supply_schematic.svg └── arduino │ └── WeatherStation │ └── WeatherStation.ino └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/.idea/.name: -------------------------------------------------------------------------------- 1 | WeatherStation -------------------------------------------------------------------------------- /Minimal (v0.1)/documents/WeatherStation.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimircea/WeatherStation/HEAD/Minimal (v0.1)/documents/WeatherStation.fzz -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Minimal (v0.1)/documents/media/full_schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimircea/WeatherStation/HEAD/Minimal (v0.1)/documents/media/full_schematic.png -------------------------------------------------------------------------------- /Minimal (v0.1)/documents/media/android_full_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimircea/WeatherStation/HEAD/Minimal (v0.1)/documents/media/android_full_screen.png -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | WeatherStation 4 | 5 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimircea/WeatherStation/HEAD/Minimal (v0.1)/android/WeatherStation/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimircea/WeatherStation/HEAD/Minimal (v0.1)/android/WeatherStation/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimircea/WeatherStation/HEAD/Minimal (v0.1)/android/WeatherStation/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimircea/WeatherStation/HEAD/Minimal (v0.1)/android/WeatherStation/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/gen/com/droid/ws/R.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package com.droid.ws; 4 | 5 | /* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */ 6 | public final class R { 7 | } -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/gen/com/droid/ws/Manifest.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package com.droid.ws; 4 | 5 | /* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */ 6 | public final class Manifest { 7 | } -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/gen/com/droid/ws/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /*___Generated_by_IDEA___*/ 2 | 3 | package com.droid.ws; 4 | 5 | /* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */ 6 | public final class BuildConfig { 7 | public final static boolean DEBUG = Boolean.parseBoolean(null); 8 | } -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/WeatherStation.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/ant.properties: -------------------------------------------------------------------------------- 1 | # This file is used to override default values used by the Ant build system. 2 | # 3 | # This file must be checked into Version Control Systems, as it is 4 | # integral to the build system of your project. 5 | 6 | # This file is only used by the Ant script. 7 | 8 | # You can use this to override default values such as 9 | # 'source.dir' for the location of your java source folder and 10 | # 'out.dir' for the location of your output folder. 11 | 12 | # You can also use it define how the release builds are signed by declaring 13 | # the following properties: 14 | # 'key.store' for the location of your keystore and 15 | # 'key.alias' for the name of the key to use. 16 | # The password will be asked during the build when you use the 'release' target. 17 | 18 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WeatherStation 2 | Implement an Arduino based WiFi "WeatherStation" with Android user interface for less than 30 EUR. 3 | 4 | This project shows how to implement a cheap (under 30 EUR) Weather Station with the help of an Arduino board (as example we use Arduino Pro Mini but other Arduino boards work as well). 5 | We use the ESP8266 WiFi module, and Arduino Pro Mini, a DHT22 humidity and temperature sensor and a few other cheap components. 6 | 7 | ## Dependencies 8 | This project requires the [DHTLib](https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib) and [Arduino-ESP8266](https://github.com/dimircea/Arduino-ESP8266) Arduino libraries. 9 | 10 | ## Hardware Design 11 | The hardware design is made by using [Fritzing](fritzing.org). The Breadboard and Schematic is ready, but the PCB Layout (for etching) is currently work in progress. All the required files are available under the `documents` folder. 12 | 13 | ## Software Design 14 | The user interface is implemented as an Android application, and the sensors data is obtained via WiFi. 15 | We only tested it with Android 4.3.1 (API 18), 4.4.2 (API 19) and 5.0.1 (API 21), and we know that it does not work with Android 2.3.3 (API 10). You are welcome to test other Android versions and report if it works or not. 16 | 17 | The WeatherSensor node uses Arduino code. 18 | 19 | ## Want to Contribute ? 20 | You are welcome to contribute! Please contact me: dimircea[at]gmail.com. 21 | 22 | ## License 23 | All the code and examples are available under the [GNU General Public License](http://www.gnu.org/licenses/gpl.html) 24 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 56 | 57 | 69 | 70 | 71 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Minimal (v0.1)/arduino/WeatherStation/WeatherStation.ino: -------------------------------------------------------------------------------- 1 | // Arduino pin number used for the communication with DHT22 sensor. 2 | // A custom 1-Wire communication protocol is used for this module. 3 | // See: https://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf 4 | #define DHT22_PIN 9 5 | 6 | // pins number for WiFi enabled/disabled LEDs 7 | #define WIFI_DISABLED_LED_PIN 7 8 | #define WIFI_ACTIVE_LED_PIN 8 9 | // arduino pin used to connect to CH_PD (Power Down) WiFi module pin 10 | #define WIFI_CH_PD_PIN 2 11 | // arduino pin used to connect to RESET WiFi module pin 12 | #define WIFI_RESET_PIN 3 13 | // interval-time (in ms) to check WiFi module (5s) 14 | #define WIFI_CHECK_TIME 5000 15 | // interval-time (in ms) to restart the WiFi ESP8266 module 16 | // in case that it become unresponsive (hardware reset required!) 17 | #define WIFI_RESTART_TIMEOUT 30000 18 | 19 | #include 20 | #include ; 21 | 22 | // keep tracking the average temperature and humidity 23 | // values, starting with last system reset 24 | float avgTemperature = 0; 25 | float avgHumidity = 0; 26 | // used to compute the averate temperature value 27 | unsigned long avgDhtStep = 1; 28 | 29 | // data template for sensors 30 | const char SENSORS_DATA_TEMPLATE[] PROGMEM = 31 | "{\"temperature\": %s, \"avgTemperature\": %s, \"humidity\": %s, \"avgHumidity\": %s, \"voltage\": %s, \"freeRam\": %d}"; 32 | 33 | // DHT22 sensor controller class 34 | dht dht22; 35 | 36 | // ESP8266 WiFi module controller 37 | ESP8266 esp( Serial); 38 | 39 | enum class Command { 40 | GET_ALL_SENSORS_DATA = 97 41 | }; 42 | 43 | /** 44 | * Check if ESP8266 (WiFi) module is active. 45 | */ 46 | boolean checkWiFi() { 47 | // try to communicate with ESP8266 module 48 | if( esp.at() == ESP8266::Error::NONE) { 49 | digitalWrite( WIFI_DISABLED_LED_PIN, LOW); 50 | digitalWrite( WIFI_ACTIVE_LED_PIN, HIGH); 51 | return true; 52 | } else { 53 | digitalWrite( WIFI_ACTIVE_LED_PIN, LOW); 54 | digitalWrite( WIFI_DISABLED_LED_PIN, HIGH); 55 | return false; 56 | } 57 | } 58 | 59 | /** 60 | * Prepare Wifi Communication: 61 | * - prepare pins for the ESP8266 module 62 | * - hardware reset ESP8266 module 63 | */ 64 | void setupWiFi() { 65 | // set pins used for WiFi status LEDs as OUTPUT 66 | pinMode( WIFI_ACTIVE_LED_PIN, OUTPUT); 67 | pinMode( WIFI_DISABLED_LED_PIN, OUTPUT); 68 | // Arduino pin connected to ESP8266 CH_PD pin is set to OUTPUT. 69 | // To keep the module active, this pin must be kept HIGH. 70 | pinMode( WIFI_CH_PD_PIN, OUTPUT); 71 | digitalWrite( WIFI_CH_PD_PIN, HIGH); 72 | // Arduino pin connected to ESP8266 RESET pin is set to OUTPUT. 73 | // To avoid random resents, we keep this HIGH. 74 | pinMode( WIFI_RESET_PIN, OUTPUT); 75 | digitalWrite( WIFI_RESET_PIN, HIGH); 76 | // perform a hardware reset (ESP8266 RESET pin goes LOW) 77 | digitalWrite( WIFI_RESET_PIN, LOW); 78 | delay( 200); 79 | // allow ESP8266 module to boot 80 | digitalWrite( WIFI_RESET_PIN, HIGH); 81 | // baud 115200, communication with ESP8266 module 82 | Serial.begin( 115200); 83 | // wait for the ESP8266 module to start, after the forced hardware reset. 84 | // We check the wifi state once a second, until the ESP8266 WiFi module responds. 85 | while( !checkWiFi()) { 86 | delay( 1000); 87 | }; 88 | // start UDP connection - wait on all ports 89 | esp.atCipstartUdp(); 90 | } 91 | 92 | /** 93 | * Read the voltage which powes the system on the 5V line. 94 | * This is possible by using the internal voltage reference 95 | * available in some ATmega MCUs such as ATmega328p 96 | */ 97 | float getVcc() { 98 | long result; 99 | // read 1.1V reference against AVcc 100 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 101 | // wait for Vref to settle 102 | delay(2); 103 | // convert 104 | ADCSRA |= _BV(ADSC); 105 | while (bit_is_set(ADCSRA,ADSC)); 106 | result = ADCL; 107 | result |= ADCH<<8; 108 | // Back-calculate AVcc in mV 109 | result = 1103700L / result; 110 | // return response in volts 111 | return result / 1000.0; 112 | } 113 | 114 | /** 115 | * Update the data (perform new reading) for 116 | * the DHT22 temperature and humidity sensor. 117 | * After calling this method, the temperature 118 | * and humidity values are available by reading 119 | * DHT.temperature and DHT.humidity. 120 | */ 121 | void updateDHTData() { 122 | if ( dht22.read22( DHT22_PIN) == DHTLIB_OK) { 123 | avgTemperature = ( avgTemperature * (avgDhtStep - 1) + dht22.temperature) / (float)avgDhtStep; 124 | avgHumidity = ( avgHumidity * (avgDhtStep - 1) + dht22.humidity) / (float)avgDhtStep; 125 | } 126 | } 127 | 128 | /** 129 | * Get the data string using a pattern and the parameter values. 130 | */ 131 | void createSensorsDataFromTemplate( char *&data) { 132 | char buffTemp[7] = {0}, buffAvgTemp[7] = {0}, buffAvgHum[7] = {0}, 133 | buffHum[7] = {0}, buffVcc[5] = {0}, tmpl[140] = {0}; 134 | char *pTmpl = tmpl; 135 | uint8_t templateLen = -1; 136 | // read template from PROGMEM 137 | getPMData( SENSORS_DATA_TEMPLATE, pTmpl, templateLen); 138 | // create data string from template by replacing 139 | // parameters with their actual values from sensors 140 | sprintf( data, pTmpl, 141 | dtostrf( dht22.temperature, 6, 1, buffTemp), 142 | dtostrf( avgTemperature, 6, 1, buffAvgTemp), 143 | dtostrf( dht22.humidity, 6, 1, buffHum), 144 | dtostrf( avgHumidity, 6, 1, buffAvgHum), 145 | dtostrf( getVcc(), 4, 2, buffVcc), 146 | getFreeMCUMemory()); 147 | } 148 | 149 | /** 150 | * Process requests (with or without parameters). 151 | * The commands are defined as constants, and 152 | * have the pattern: CMD_command_name. 153 | * @param data 154 | * the data to be processed (+IPD: 155 | */ 156 | void processRequest( char *data) { 157 | char progmemData[150] = {0}; 158 | char *pData = progmemData; 159 | // first char represents the command 160 | char cmd = *(data); 161 | switch ( (Command)cmd) { 162 | case Command::GET_ALL_SENSORS_DATA: 163 | createSensorsDataFromTemplate( pData); 164 | esp.atCipsend( pData); 165 | break; 166 | default: 167 | // nothing to do ... 168 | break; 169 | } 170 | } 171 | 172 | /** 173 | * Prepare ths system. This method is called when the system starts. 174 | */ 175 | void setup() { 176 | // setup WiFi - ESP8266 module 177 | setupWiFi(); 178 | // Get initial data (temperature & humidity) from DHT22 sensor. 179 | // Add a 2 seconds delay to prevent timeouts from the sensor. 180 | delay( 2000); 181 | updateDHTData(); 182 | } 183 | 184 | /** 185 | * Loop method which executes again and again. 186 | */ 187 | void loop() { 188 | // Incomming real data via IPD is 1 byte (the command identifier byte). 189 | // The first bytes are: "+IPD,n:", followed by the real data 190 | char data[10] = {0}, *ipdData = data; 191 | // Incomming data from ESP8266 module 192 | // Lengt must be greater than 7 bytes ("+IPD,n:") 193 | if ( Serial.available() > 7) { 194 | // process request received from UDP port: (wait 50ms for data) 195 | if ( esp.ipd( ipdData) == ESP8266::Error::NONE) { 196 | // process the request 197 | processRequest( ipdData); 198 | } 199 | } 200 | // a small delay before checking againd for WiFi incomming data 201 | delay( 25); 202 | } 203 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/src/com/droid/ws/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.droid.ws; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import java.net.InetAddress; 6 | import android.net.wifi.WifiManager; 7 | import android.net.DhcpInfo; 8 | import java.io.IOException; 9 | import android.content.Context; 10 | import android.util.Log; 11 | import android.view.WindowManager; 12 | import android.view.Window; 13 | 14 | import java.net.DatagramSocket; 15 | import java.net.DatagramPacket; 16 | import java.text.SimpleDateFormat; 17 | import java.util.Date; 18 | 19 | import android.widget.*; 20 | import org.json.JSONException; 21 | import org.json.JSONObject; 22 | import android.view.View; 23 | 24 | 25 | public class MainActivity extends Activity { 26 | int udpPort = 1025; 27 | DatagramSocket socket; 28 | 29 | TextView sensorsDataReceivedTimeTextView; 30 | TextView temperatureValueTextView; 31 | TextView avgTemperatureValueTextView; 32 | TextView humidityValueTextView; 33 | TextView avgHumidityValueTextView; 34 | TextView voltageValueTextView; 35 | TextView freeRamValueTextView; 36 | 37 | Button refreshButton; 38 | Switch preventScreenLockSwitch; 39 | 40 | boolean appInBackground = false; 41 | boolean doneEditing = true; 42 | 43 | @Override 44 | protected void onResume() { 45 | super.onResume(); 46 | appInBackground = false; 47 | } 48 | 49 | @Override 50 | protected void onPause() { 51 | super.onPause(); 52 | appInBackground = true; 53 | } 54 | 55 | /** 56 | * Called when the activity is first created. 57 | */ 58 | @Override 59 | public void onCreate( Bundle savedInstanceState) { 60 | super.onCreate(savedInstanceState); 61 | setContentView(R.layout.main); 62 | // disable auto turn screen off feature 63 | final Window window = getWindow(); 64 | window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); // Turn screen on if off 65 | window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // Keep screen on 66 | 67 | sensorsDataReceivedTimeTextView = (TextView) findViewById(R.id.sensorsDataReceivedTimeTextView); 68 | temperatureValueTextView = (TextView) findViewById(R.id.temperatureValueTextView); 69 | avgTemperatureValueTextView = (TextView) findViewById(R.id.avgTemperatureValueTextView); 70 | humidityValueTextView = (TextView) findViewById(R.id.humidityValueTextView); 71 | avgHumidityValueTextView = (TextView) findViewById(R.id.avgHumidityValueTextView); 72 | voltageValueTextView = (TextView) findViewById(R.id.voltageValueTextView); 73 | freeRamValueTextView = (TextView) findViewById(R.id.freeRamValueTextView); 74 | refreshButton = (Button) findViewById(R.id.refreshButton); 75 | preventScreenLockSwitch = (Switch) findViewById(R.id.preventScreenLockSwitch); 76 | 77 | // request sensors data from WoT sensors node 78 | (new Thread(new Runnable() { 79 | @Override 80 | public void run() { 81 | try { 82 | socket = new DatagramSocket(udpPort); 83 | while (true) { 84 | if (appInBackground) { 85 | continue; 86 | } 87 | try { 88 | sendUdpData(Commands.GET_ALL_SENSORS_DATA, null); 89 | Thread.sleep(10000); 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | } 94 | } catch (Exception e) { 95 | e.printStackTrace(); 96 | } 97 | } 98 | })).start(); 99 | 100 | // listen for data from requesting data from WoT sensors node 101 | (new Thread(new Runnable() { 102 | @Override 103 | public void run() { 104 | while (true) { 105 | if (appInBackground) { 106 | continue; 107 | } 108 | DatagramPacket udpPacket = receiveUdpData(); 109 | if (udpPacket == null) { 110 | continue; 111 | } 112 | String udpPacketData = new String( udpPacket.getData()); 113 | try { 114 | JSONObject jsonObj = new JSONObject(udpPacketData); 115 | updateUserInterface( jsonObj); 116 | } catch ( JSONException e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | } 121 | })).start(); 122 | 123 | refreshButton.setOnClickListener(new View.OnClickListener() { 124 | public void onClick(View v) { 125 | // request data from WoT sensors node 126 | (new Thread(new Runnable() { 127 | @Override 128 | public void run() { 129 | try { 130 | sendUdpData( Commands.GET_ALL_SENSORS_DATA, null); 131 | } catch (Exception e) { 132 | e.printStackTrace(); 133 | } 134 | } 135 | })).start(); 136 | } 137 | }); 138 | 139 | preventScreenLockSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 140 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 141 | if (isChecked) { 142 | window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 143 | } else { 144 | getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 145 | } 146 | } 147 | }); 148 | } 149 | 150 | void updateUserInterface( final JSONObject jsonObj) { 151 | try { 152 | final double temperature = jsonObj.getDouble("temperature"); 153 | final double avgTemperature = jsonObj.getDouble("avgTemperature"); 154 | final double humidity = jsonObj.getDouble("humidity"); 155 | final double avgHumidity = jsonObj.getDouble("avgHumidity"); 156 | final double voltage = jsonObj.getDouble("voltage"); 157 | final int freeRam = jsonObj.getInt("freeRam"); 158 | 159 | sensorsDataReceivedTimeTextView.post(new Runnable() { 160 | public void run() { 161 | SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 162 | sensorsDataReceivedTimeTextView.setText(dateFormat.format(new Date())); 163 | } 164 | }); 165 | temperatureValueTextView.post(new Runnable() { 166 | public void run() { 167 | temperatureValueTextView.setText(String.valueOf(temperature) + "°C"); 168 | } 169 | }); 170 | avgTemperatureValueTextView.post(new Runnable() { 171 | public void run() { 172 | avgTemperatureValueTextView.setText(String.valueOf(avgTemperature) + "°C"); 173 | } 174 | }); 175 | humidityValueTextView.post(new Runnable() { 176 | public void run() { 177 | humidityValueTextView.setText(String.valueOf(humidity) + "%"); 178 | } 179 | }); 180 | avgHumidityValueTextView.post(new Runnable() { 181 | public void run() { 182 | avgHumidityValueTextView.setText(String.valueOf(avgHumidity) + "%"); 183 | } 184 | }); 185 | voltageValueTextView.post(new Runnable() { 186 | public void run() { 187 | voltageValueTextView.setText(String.valueOf(voltage) + "V"); 188 | } 189 | }); 190 | freeRamValueTextView.post(new Runnable() { 191 | public void run() { 192 | freeRamValueTextView.setText(String.valueOf(freeRam) + "Bytes"); 193 | } 194 | }); 195 | } catch (JSONException e) { 196 | e.printStackTrace(); 197 | } 198 | } 199 | 200 | InetAddress getBroadcastAddress() throws IOException { 201 | WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE); 202 | DhcpInfo dhcp = wifi.getDhcpInfo(); 203 | // no DHCP info...can't do nothing more 204 | if ( dhcp == null) { 205 | return null; 206 | } 207 | int ipAddress = dhcp.gateway; 208 | byte[] ipQuads = new byte[4]; 209 | ipQuads[0] = (byte)(ipAddress & 0xFF);; 210 | ipQuads[1] = (byte)((ipAddress >> 8) & 0xFF); 211 | ipQuads[2] = (byte)((ipAddress >> 16) & 0xFF); 212 | ipQuads[3] = (byte)((ipAddress >> 24) & 0xFF); 213 | 214 | /* 192.168.4.1 = [ -64, -88, 4, 1] */ 215 | return InetAddress.getByAddress( ipQuads); 216 | } 217 | 218 | void sendUdpData( Commands cmd, byte[] params) { 219 | try { 220 | final DatagramPacket packet; 221 | int paramsLength = ( params != null ? params.length : 0); 222 | byte data[] = new byte[paramsLength + 1]; 223 | byte command[] = new byte[1]; 224 | command[0] = cmd.getValue(); 225 | System.arraycopy( command, 0, data, 0, command.length); 226 | if ( params != null) { 227 | System.arraycopy(params, 0, data, 1, params.length); 228 | } 229 | packet = new DatagramPacket( data, data.length, 230 | getBroadcastAddress(), udpPort); 231 | socket.send( packet); 232 | } catch( IOException e){ 233 | e.printStackTrace(); 234 | } 235 | } 236 | 237 | DatagramPacket receiveUdpData() { 238 | try { 239 | byte[] data = new byte[1024]; 240 | DatagramPacket packet = new DatagramPacket( data, data.length); 241 | if ( socket == null) { 242 | return null; 243 | } 244 | socket.receive(packet); 245 | Log.i("HD:receiveUdpData", new String( packet.getData()).trim()); 246 | return packet; 247 | } catch( IOException e){ 248 | Log.e("HD:receiveUdpData", "Error occurred when receiving UDP data on port: " + udpPort); 249 | e.printStackTrace(); 250 | return null; 251 | } 252 | } 253 | 254 | /** 255 | * Define the set of commands which can be send to the WoT sensor(s) node. 256 | */ 257 | enum Commands { 258 | GET_ALL_SENSORS_DATA ( (byte)97); 259 | private final byte id; 260 | Commands( byte id) { this.id = id; } 261 | public byte getValue() { return id; } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /Minimal (v0.1)/android/WeatherStation/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 14 | 18 | 25 | 32 | 33 | 34 | 37 | 43 | 49 | 50 | 51 | 55 | 56 | 59 | 65 | 71 | 72 | 73 | 77 | 78 | 81 | 87 | 92 | 93 | 94 | 98 | 99 | 102 | 108 | 113 | 114 | 115 | 119 | 120 | 123 | 129 | 135 | 136 | 137 | 141 | 142 | 145 | 146 | 152 | 158 | 159 | 160 | 164 | 169 |