From 3320eec6de4dff67af88ec155c6f4280dc024d76 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Thu, 23 Mar 2023 22:42:48 +0000 Subject: [PATCH 01/25] config and helpers created --- enviro/config_defaults.py | 38 ++++++++++++++++++++++++++--- enviro/config_template.py | 6 ++++- enviro/destinations/wunderground.py | 21 ++++++++++++++++ enviro/helpers.py | 12 +++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 enviro/destinations/wunderground.py diff --git a/enviro/config_defaults.py b/enviro/config_defaults.py index 63a5877..b29edc4 100644 --- a/enviro/config_defaults.py +++ b/enviro/config_defaults.py @@ -2,6 +2,8 @@ from phew import logging DEFAULT_USB_POWER_TEMPERATURE_OFFSET = 4.5 +DEFAULT_UTC_OFFSET = 0 +DEFAULT_UK_BST = True def add_missing_config_settings(): @@ -19,10 +21,40 @@ def add_missing_config_settings(): config.usb_power_temperature_offset = DEFAULT_USB_POWER_TEMPERATURE_OFFSET try: - config.wifi_country + config.wunderground_id except AttributeError: - warn_missing_config_setting("wifi_country") - config.wifi_country = "GB" + warn_missing_config_setting("wunderground_id") + config.wunderground_id = None + + try: + config.wunderground_key + except AttributeError: + warn_missing_config_setting("wunderground_key") + config.wunderground_key = None + + try: + config.sea_level_pressure + except AttributeError: + warn_missing_config_setting("sea_level_pressure") + config.sea_level_pressure = False + + try: + config.height_above_sea_level + except AttributeError: + warn_missing_config_setting("height_above_sea_level") + config.height_above_sea_level = 0 + + try: + config.uk_bst + except AttributeError: + warn_missing_config_setting("uk_bst") + config.uk_bst = DEFAULT_UK_BST + + try: + config.utc_offset + except AttributeError: + warn_missing_config_setting("utc_offset") + config.utc_offset = DEFAULT_UTC_OFFSET def warn_missing_config_setting(setting): logging.warn(f"> config setting '{setting}' missing, please add it to config.py") diff --git a/enviro/config_template.py b/enviro/config_template.py index 11404a9..a4841c1 100644 --- a/enviro/config_template.py +++ b/enviro/config_template.py @@ -19,7 +19,7 @@ # how often to trigger a resync of the onboard RTC (in hours) resync_frequency = 168 -# where to upload to ("http", "mqtt", "adafruit_io", "influxdb") +# where to upload to ("http", "mqtt", "adafruit_io", "influxdb", "weather_underground") destination = None # how often to upload data (number of cached readings) @@ -47,6 +47,10 @@ influxdb_token = None influxdb_bucket = None +# weather underground settings +wunderground_id = None +wunderground_key = None + # grow specific settings auto_water = False moisture_target_a = 50 diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py new file mode 100644 index 0000000..b0d87a8 --- /dev/null +++ b/enviro/destinations/wunderground.py @@ -0,0 +1,21 @@ +from enviro import logging +from enviro.constants import UPLOAD_SUCCESS, UPLOAD_FAILED +import urequests, time +import config +from helpers import celcius_to_fahrenheit, hpa_to_inches, metres_per_second_to_miles_per_hour, mm_to_inches + +def url_encode(t): + result = "" + for c in t: + # no encoding needed for character + if c.isalpha() or c.isdigit() or c in ["-", "_", "."]: + result += c + elif c == " ": + result += "+" + else: + result += f"%{ord(c):02X}" + return result + +def log_destination(): + logging.info(f"> uploading cached readings to Weather Underground device: {config.wunderground_id}") + diff --git a/enviro/helpers.py b/enviro/helpers.py index 1503ad4..1dc96bd 100644 --- a/enviro/helpers.py +++ b/enviro/helpers.py @@ -77,6 +77,18 @@ def absolute_to_relative_humidity(absolute_humidity, temperature_in_c): def celcius_to_kelvin(temperature_in_c): return temperature_in_c + 273.15 +def celcius_to_fahrenheit(temperature_in_c): + return temperature_in_c * 1.8 + 32 + +def hpa_to_inches(pressure_in_hpa): + return pressure_in_hpa * 0.02953 + +def metres_per_second_to_miles_per_hour(speed_in_mps): + return speed_in_mps * 2.2369362912 + +def mm_to_inches(distance_in_mm): + return distance_in_mm * 0.0393700787 + # https://www.calctool.org/atmospheric-thermodynamics/absolute-humidity#actual-vapor-pressure # http://cires1.colorado.edu/~voemel/vp.html def get_actual_vapor_pressure(relative_humidity, temperature_in_k): From b699378486051a1d141ef1d6ddf7f54e1e06bb02 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 25 Mar 2023 13:42:18 +0000 Subject: [PATCH 02/25] Working dummy wunderground destination --- enviro/config_template.py | 2 +- enviro/destinations/wunderground.py | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/enviro/config_template.py b/enviro/config_template.py index a4841c1..29e5c4d 100644 --- a/enviro/config_template.py +++ b/enviro/config_template.py @@ -19,7 +19,7 @@ # how often to trigger a resync of the onboard RTC (in hours) resync_frequency = 168 -# where to upload to ("http", "mqtt", "adafruit_io", "influxdb", "weather_underground") +# where to upload to ("http", "mqtt", "adafruit_io", "influxdb", "wunderground") destination = None # how often to upload data (number of cached readings) diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py index b0d87a8..ec3bceb 100644 --- a/enviro/destinations/wunderground.py +++ b/enviro/destinations/wunderground.py @@ -2,7 +2,7 @@ from enviro.constants import UPLOAD_SUCCESS, UPLOAD_FAILED import urequests, time import config -from helpers import celcius_to_fahrenheit, hpa_to_inches, metres_per_second_to_miles_per_hour, mm_to_inches +import enviro.helpers def url_encode(t): result = "" @@ -19,3 +19,21 @@ def url_encode(t): def log_destination(): logging.info(f"> uploading cached readings to Weather Underground device: {config.wunderground_id}") +def upload_reading(reading): + for key, value in reading["readings"].items(): + timestamp = reading["timestamp"] + + year = timestamp[0:4] + month = timestamp[5:7] + day = timestamp[8:10] + hour = timestamp[11:13] + minute = timestamp[14:16] + second = timestamp[17:19] + + timestamp = year + "-" + month+ "-" + day + "+" + hour + "%3A" + minute + "%3A" + second + + url = "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=" + config.wunderground_id + "&PASSWORD=" + config.wunderground_key + "&dateutc=" + timestamp + + logging.info(f"> upload url: {url}") + + return UPLOAD_SUCCESS \ No newline at end of file From 36b6c3d93d904c3b7e21d6cb1533a90c903d7f28 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 25 Mar 2023 15:02:29 +0000 Subject: [PATCH 03/25] Working wunderground destination --- enviro/destinations/wunderground.py | 75 +++++++++++++++++++---------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py index ec3bceb..91e1ac5 100644 --- a/enviro/destinations/wunderground.py +++ b/enviro/destinations/wunderground.py @@ -1,39 +1,64 @@ from enviro import logging from enviro.constants import UPLOAD_SUCCESS, UPLOAD_FAILED -import urequests, time +import urequests import config -import enviro.helpers - -def url_encode(t): - result = "" - for c in t: - # no encoding needed for character - if c.isalpha() or c.isdigit() or c in ["-", "_", "."]: - result += c - elif c == " ": - result += "+" - else: - result += f"%{ord(c):02X}" - return result +from enviro.helpers import celcius_to_fahrenheit, hpa_to_inches, metres_per_second_to_miles_per_hour def log_destination(): logging.info(f"> uploading cached readings to Weather Underground device: {config.wunderground_id}") +def get_wunderground_timestamp(enviro_timestamp): + year = enviro_timestamp[0:4] + month = enviro_timestamp[5:7] + day = enviro_timestamp[8:10] + hour = enviro_timestamp[11:13] + minute = enviro_timestamp[14:16] + second = enviro_timestamp[17:19] + timestamp = year + "-" + month+ "-" + day + "+" + hour + "%3A" + minute + "%3A" + second + return timestamp + +# API documentation https://support.weather.com/s/article/PWS-Upload-Protocol?language=en_GB def upload_reading(reading): - for key, value in reading["readings"].items(): - timestamp = reading["timestamp"] + timestamp = get_wunderground_timestamp(reading["timestamp"]) + + url = "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=" + config.wunderground_id + "&PASSWORD=" + config.wunderground_key + "&dateutc=" + timestamp + "&softwaretype=EnviroWeather&action=updateraw" - year = timestamp[0:4] - month = timestamp[5:7] - day = timestamp[8:10] - hour = timestamp[11:13] - minute = timestamp[14:16] - second = timestamp[17:19] + # convert and append applicable readings to URL + for key, value in reading["readings"].items(): + if key == "temperature": + url += "&tempf=" + str(celcius_to_fahrenheit(value)) - timestamp = year + "-" + month+ "-" + day + "+" + hour + "%3A" + minute + "%3A" + second + if key == "humidity": + # Humidity can exceed 100% but API states 0-100 accepted values + if value > 100: + value = 100 + url += "&humidity=" + str(value) + + if key == "pressure": + url += "&baromin=" + str(hpa_to_inches(value)) + + if key == "wind_speed": + url += "&windspeedmph=" + str(metres_per_second_to_miles_per_hour(value)) - url = "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=" + config.wunderground_id + "&PASSWORD=" + config.wunderground_key + "&dateutc=" + timestamp + if key == "wind_direction": + url += "&winddir=" + str(value) + + #TODO Potentially able to convert luminance to solar radiation (solarradiation - [W/m^2]) + #TODO Work out if the file in the rain trigger can be used to calculate and send (rainin - [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min) logging.info(f"> upload url: {url}") - return UPLOAD_SUCCESS \ No newline at end of file + try: + # send (GET) reading data to http endpoint + result = urequests.get(url) + + logging.debug(f" - Result ({result.status_code} {result.reason})") + + if result.status_code == 200: + return UPLOAD_SUCCESS + + logging.debug(f" - upload issue ({result.status_code} {result.reason})") + except: + logging.debug(f" - an exception occurred when uploading") + + return UPLOAD_FAILED \ No newline at end of file From f4c5a3af23fa5f549583ba153e991ad6d12c0775 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 25 Mar 2023 15:22:34 +0000 Subject: [PATCH 04/25] Documentation --- documentation/destinations/wunderground.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 documentation/destinations/wunderground.md diff --git a/documentation/destinations/wunderground.md b/documentation/destinations/wunderground.md new file mode 100644 index 0000000..77d5022 --- /dev/null +++ b/documentation/destinations/wunderground.md @@ -0,0 +1,18 @@ +# Weather Underground + +Contracted to "wunderground in config and code" Weather Underground is a web service run by IBM for uploading and viewing information from personal Weather Stations (PWS). + +You can sign up for a free acount, configure a device and drop the credentials into the Enviro configuration to have the values appear on your own weather station dashboard that is also shared with the world. + +## Setting up a Weather Underground account and device + +1. Visit [Weather Underground](https://www.wunderground.com/) +2. Create an account by clicking [Join](https://www.wunderground.com/signup) in the navigation bar. +3. Create your account using your email and a new password +4. Browse to your [devices](https://www.wunderground.com/member/devices) in your profile +5. Click Add New Device - Select Raspberry Pi as device hardware and follow the wizard selecting appropriate values (if in doubt, go American units) +6. Credentials are displayed on the summary screen, but you can check these at any time on the device page + +When you provision your device enter the station ID and station key and Enviro will automatically start sending data on the schedule you have requested. + +You can view the dashboard for your station by clicking the station name on the [devices](https://www.wunderground.com/member/devices) page. \ No newline at end of file From de4831867363f6e7711f1bd6747d10ae4a5c55b2 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Mon, 20 Mar 2023 14:38:41 +0000 Subject: [PATCH 05/25] Add sea level pressure calculation --- enviro/boards/weather.py | 16 +++++++++++++--- enviro/config_template.py | 5 +++++ enviro/helpers.py | 7 +++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index 9b44e13..8714830 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -3,7 +3,7 @@ from breakout_ltr559 import BreakoutLTR559 from machine import Pin, PWM from pimoroni import Analog -from enviro import i2c, activity_led +from enviro import i2c, activity_led, config import enviro.helpers as helpers from phew import logging from enviro.constants import WAKE_REASON_RTC_ALARM, WAKE_REASON_BUTTON_PRESS @@ -190,11 +190,21 @@ def get_sensor_readings(seconds_since_last, is_usb_power): ltr_data = ltr559.get_reading() rain, rain_per_second = rainfall(seconds_since_last) + # Adjust pressure to calculated sea level value if set to in config + pressure = round(bme280_data[1] / 100.0, 2) + temperature = round(bme280_data[0], 2) + + if config.sea_level_pressure: + logging.info(f" - recorded temperature: {temperature}") + logging.info(f" - recorded pressure: {pressure}") + pressure = round(helpers.get_sea_level_pressure(pressure, temperature, config.height_above_sea_level), 2) + logging.info(f" - calculated mean sea level pressure: {pressure}") + from ucollections import OrderedDict return OrderedDict({ - "temperature": round(bme280_data[0], 2), + "temperature": temperature, "humidity": round(bme280_data[2], 2), - "pressure": round(bme280_data[1] / 100.0, 2), + "pressure": pressure, "luminance": round(ltr_data[BreakoutLTR559.LUX], 2), "wind_speed": wind_speed(), "rain": rain, diff --git a/enviro/config_template.py b/enviro/config_template.py index 29e5c4d..fd27bd6 100644 --- a/enviro/config_template.py +++ b/enviro/config_template.py @@ -59,3 +59,8 @@ # compensate for usb power usb_power_temperature_offset = 4.5 + +# sea level pressure conversion (adjusts measured pressure output for mean sea level value) +sea_level_pressure = False +# height in metres +height_above_sea_level = 0 \ No newline at end of file diff --git a/enviro/helpers.py b/enviro/helpers.py index 1dc96bd..fb89f8c 100644 --- a/enviro/helpers.py +++ b/enviro/helpers.py @@ -110,3 +110,10 @@ def get_saturation_vapor_pressure(temperature_in_k): temperature_in_k * (a1*v + a2*v**1.5 + a3*v**3 + a4*v**3.5 + a5*v**4 + a6*v**7.5) ) + +# Calculates mean sea level pressure (QNH) from observed pressure +# https://keisan.casio.com/exec/system/1224575267 +def get_sea_level_pressure(observed_pressure, temperature_in_c, altitude_in_m): +# def sea(pressure, temperature, height): + qnh = observed_pressure * ((1 - ((0.0065 * altitude_in_m) / (temperature_in_c + (0.0065 * altitude_in_m) + 273.15)))** -5.257) + return qnh \ No newline at end of file From 024abafc92d0f6afbf4015a9b7a7b66685c31292 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Mon, 20 Mar 2023 18:25:16 +0000 Subject: [PATCH 06/25] Reduce rounding error --- enviro/boards/weather.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index 8714830..3c9f8c6 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -191,8 +191,8 @@ def get_sensor_readings(seconds_since_last, is_usb_power): rain, rain_per_second = rainfall(seconds_since_last) # Adjust pressure to calculated sea level value if set to in config - pressure = round(bme280_data[1] / 100.0, 2) - temperature = round(bme280_data[0], 2) + pressure = bme280_data[1] / 100.0 + temperature = bme280_data[0] if config.sea_level_pressure: logging.info(f" - recorded temperature: {temperature}") @@ -202,9 +202,9 @@ def get_sensor_readings(seconds_since_last, is_usb_power): from ucollections import OrderedDict return OrderedDict({ - "temperature": temperature, + "temperature": round(temperature, 2), "humidity": round(bme280_data[2], 2), - "pressure": pressure, + "pressure": round(pressure, 2), "luminance": round(ltr_data[BreakoutLTR559.LUX], 2), "wind_speed": wind_speed(), "rain": rain, From f7fa3731307929dfcce828441b55bc95d91651ef Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Fri, 24 Mar 2023 14:42:59 +0000 Subject: [PATCH 07/25] Return sea level in new reading key --- enviro/boards/weather.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index 3c9f8c6..42a81f7 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -193,15 +193,9 @@ def get_sensor_readings(seconds_since_last, is_usb_power): # Adjust pressure to calculated sea level value if set to in config pressure = bme280_data[1] / 100.0 temperature = bme280_data[0] - - if config.sea_level_pressure: - logging.info(f" - recorded temperature: {temperature}") - logging.info(f" - recorded pressure: {pressure}") - pressure = round(helpers.get_sea_level_pressure(pressure, temperature, config.height_above_sea_level), 2) - logging.info(f" - calculated mean sea level pressure: {pressure}") from ucollections import OrderedDict - return OrderedDict({ + readings = OrderedDict({ "temperature": round(temperature, 2), "humidity": round(bme280_data[2], 2), "pressure": round(pressure, 2), @@ -211,3 +205,12 @@ def get_sensor_readings(seconds_since_last, is_usb_power): "rain_per_second": rain_per_second, "wind_direction": wind_direction() }) + + if config.sea_level_pressure: + logging.info(f" - recorded temperature: {temperature}") + logging.info(f" - recorded pressure: {pressure}") + sea_level_pressure = round(helpers.get_sea_level_pressure(pressure, temperature, config.height_above_sea_level), 2) + logging.info(f" - calculated mean sea level pressure: {sea_level_pressure}") + readings["sea_level_pressure"] = round(sea_level_pressure, 2) + + return readings \ No newline at end of file From 1b5cc66a539e56ae42898a61504c1ebd1177bb70 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 25 Mar 2023 15:33:50 +0000 Subject: [PATCH 08/25] Added sea level pressure to wunderground --- documentation/destinations/wunderground.md | 2 ++ enviro/destinations/wunderground.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/destinations/wunderground.md b/documentation/destinations/wunderground.md index 77d5022..af664af 100644 --- a/documentation/destinations/wunderground.md +++ b/documentation/destinations/wunderground.md @@ -15,4 +15,6 @@ You can sign up for a free acount, configure a device and drop the credentials i When you provision your device enter the station ID and station key and Enviro will automatically start sending data on the schedule you have requested. +Ensure you have enabled the sea level pressure option and provided accurate [elevation data](https://whatismyelevation.com/) if you want to return pressure data. + You can view the dashboard for your station by clicking the station name on the [devices](https://www.wunderground.com/member/devices) page. \ No newline at end of file diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py index 91e1ac5..df7527e 100644 --- a/enviro/destinations/wunderground.py +++ b/enviro/destinations/wunderground.py @@ -34,7 +34,7 @@ def upload_reading(reading): value = 100 url += "&humidity=" + str(value) - if key == "pressure": + if key == "sea_level_pressure": url += "&baromin=" + str(hpa_to_inches(value)) if key == "wind_speed": From bd22b2ccc0aad8bfac189e2d64156e2b5fc69b23 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 25 Mar 2023 15:45:53 +0000 Subject: [PATCH 09/25] Supported readings and typos --- documentation/destinations/wunderground.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/documentation/destinations/wunderground.md b/documentation/destinations/wunderground.md index af664af..f00bc3d 100644 --- a/documentation/destinations/wunderground.md +++ b/documentation/destinations/wunderground.md @@ -1,20 +1,30 @@ # Weather Underground -Contracted to "wunderground in config and code" Weather Underground is a web service run by IBM for uploading and viewing information from personal Weather Stations (PWS). +Referred to as "wunderground in config and code", Weather Underground is an online service provided by IBM for uploading and viewing information from personal Weather Stations (PWS) and provides general weather forecasts and news. -You can sign up for a free acount, configure a device and drop the credentials into the Enviro configuration to have the values appear on your own weather station dashboard that is also shared with the world. +You can sign up for a free account, configure a device and drop the credentials into the Enviro configuration to have the values appear on your own weather station dashboard that is also shared with the world. ## Setting up a Weather Underground account and device 1. Visit [Weather Underground](https://www.wunderground.com/) -2. Create an account by clicking [Join](https://www.wunderground.com/signup) in the navigation bar. +2. Create an account by clicking [Join](https://www.wunderground.com/signup) in the navigation bar 3. Create your account using your email and a new password 4. Browse to your [devices](https://www.wunderground.com/member/devices) in your profile -5. Click Add New Device - Select Raspberry Pi as device hardware and follow the wizard selecting appropriate values (if in doubt, go American units) +5. Click Add New Device - Select "Raspberry Pi" as the device hardware and follow the wizard selecting appropriate values (if in doubt, go American units) 6. Credentials are displayed on the summary screen, but you can check these at any time on the device page When you provision your device enter the station ID and station key and Enviro will automatically start sending data on the schedule you have requested. Ensure you have enabled the sea level pressure option and provided accurate [elevation data](https://whatismyelevation.com/) if you want to return pressure data. -You can view the dashboard for your station by clicking the station name on the [devices](https://www.wunderground.com/member/devices) page. \ No newline at end of file +You can view the dashboard for your station by clicking the station name on the [devices](https://www.wunderground.com/member/devices) page. + +## Supported readings +The following readings will be uploaded. Depending on board type, other readings may be collected, but not sent to Weather Underground and essentially dropped. +- Temperature +- Humidity +- Sea level pressure +- Wind speed +- Wind direction + +There is potential to build logic to calculate rain per hour and convert luminance to solar radiation to capture all Enviro Weather sensor output, other boards may not be well suited to this destination. \ No newline at end of file From 140ab57ae836b857e7bbf4828c8498d5a20a207b Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 25 Mar 2023 16:57:44 +0000 Subject: [PATCH 10/25] wunderground provisioning --- enviro/html/provision-step-4-destination.html | 18 ++++++++++++++++++ enviro/provisioning.py | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/enviro/html/provision-step-4-destination.html b/enviro/html/provision-step-4-destination.html index afacdc4..c6832ac 100644 --- a/enviro/html/provision-step-4-destination.html +++ b/enviro/html/provision-step-4-destination.html @@ -28,6 +28,10 @@

Where are you uploading your data to?

Adafruit IO

A platform designed by our friends at Adafruit to store and display your data.

+
  • + Weather Underground +

    A public website hosted by IBM to upload and publish private weather station data.

    +
  • @@ -105,6 +109,20 @@

    HTTP authentication credentials (optional).

    + +
    +

    Enter your Weather Underground Station ID.

    + +
    + +
    +
    +

    Enter your Weather Underground station key.

    + +
    + +
    +
    diff --git a/enviro/provisioning.py b/enviro/provisioning.py index 1baaef2..3ab13be 100644 --- a/enviro/provisioning.py +++ b/enviro/provisioning.py @@ -123,6 +123,10 @@ def provision_step_4_destination(request): config.influxdb_url = request.form["influxdb_url"] config.influxdb_token = request.form["influxdb_token"] config.influxdb_bucket = request.form["influxdb_bucket"] + + # wunderground + config.wunderground_id = request.form["wunderground_id"] + config.wunderground_key = request.form["wunderground_key"] write_config() From c4b0fab8825e15234bc865bd699021f77818b4f4 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Wed, 29 Mar 2023 22:53:20 +0100 Subject: [PATCH 11/25] Add rain per hour and day results --- enviro/boards/weather.py | 87 +++++++++++++++++++++------------------- enviro/helpers.py | 4 ++ 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index 42a81f7..e9d3155 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -25,6 +25,28 @@ rain_pin = Pin(10, Pin.IN, Pin.PULL_DOWN) last_rain_trigger = False +def log_rain(): + # read the current rain entries + rain_entries = [] + if helpers.file_exists("rain.txt"): + with open("rain.txt", "r") as rainfile: + rain_entries = rainfile.read().split("\n") + + # add new entry + logging.info(f"> add new rain trigger at {helpers.datetime_string()}") + rain_entries.append(helpers.datetime_string()) + + # limit number of entries to 190 - each entry is 21 bytes including + # newline so this keeps the total rain.txt filesize just under one + # filesystem block (4096 bytes) + if len(rain_entries) > 190: + logging.info("Rain log file exceeded 190 entries and was truncated") + rain_entries = rain_entries[-190:] + + # write out adjusted rain log + with open("rain.txt", "w") as rainfile: + rainfile.write("\n".join(rain_entries)) + def startup(reason): global last_rain_trigger import wakeup @@ -33,24 +55,7 @@ def startup(reason): rain_sensor_trigger = wakeup.get_gpio_state() & (1 << 10) if rain_sensor_trigger: - # read the current rain entries - rain_entries = [] - if helpers.file_exists("rain.txt"): - with open("rain.txt", "r") as rainfile: - rain_entries = rainfile.read().split("\n") - - # add new entry - logging.info(f"> add new rain trigger at {helpers.datetime_string()}") - rain_entries.append(helpers.datetime_string()) - - # limit number of entries to 190 - each entry is 21 bytes including - # newline so this keeps the total rain.txt filesize just under one - # filesystem block (4096 bytes) - rain_entries = rain_entries[-190:] - - # write out adjusted rain log - with open("rain.txt", "w") as rainfile: - rainfile.write("\n".join(rain_entries)) + log_rain() last_rain_trigger = True @@ -70,24 +75,7 @@ def check_trigger(): time.sleep(0.05) activity_led(0) - # read the current rain entries - rain_entries = [] - if helpers.file_exists("rain.txt"): - with open("rain.txt", "r") as rainfile: - rain_entries = rainfile.read().split("\n") - - # add new entry - logging.info(f"> add new rain trigger at {helpers.datetime_string()}") - rain_entries.append(helpers.datetime_string()) - - # limit number of entries to 190 - each entry is 21 bytes including - # newline so this keeps the total rain.txt filesize just under one - # filesystem block (4096 bytes) - rain_entries = rain_entries[-190:] - - # write out adjusted rain log - with open("rain.txt", "w") as rainfile: - rainfile.write("\n".join(rain_entries)) + log_rain() last_rain_trigger = rain_sensor_trigger @@ -159,26 +147,41 @@ def wind_direction(): return closest_index * 45 def rainfall(seconds_since_last): + new_rain_entries = [] amount = 0 + per_hour = 0 + today = 0 now = helpers.timestamp(helpers.datetime_string()) + now_day = helpers.timestamp_day(helpers.datetime_string()) if helpers.file_exists("rain.txt"): with open("rain.txt", "r") as rainfile: rain_entries = rainfile.read().split("\n") - # count how many rain ticks since the last reading + # process the rain file data for entry in rain_entries: if entry: ts = helpers.timestamp(entry) + tsday = helpers.timestamp_day(entry) + # count how many rain ticks since the last reading if now - ts < seconds_since_last: amount += RAIN_MM_PER_TICK - - os.remove("rain.txt") + # count how many rain ticks in the last hour + if now - ts < 3600: + per_hour += RAIN_MM_PER_TICK + # count how many rain ticks today and delete older entries + if tsday == now_day: + today += RAIN_MM_PER_TICK + new_rain_entries.append(entry) + + # write out adjusted rain log + with open("rain.txt", "w") as newrainfile: + newrainfile.write("\n".join(new_rain_entries)) per_second = 0 if seconds_since_last > 0: per_second = amount / seconds_since_last - return amount, per_second + return amount, per_second, per_hour, today def get_sensor_readings(seconds_since_last, is_usb_power): # bme280 returns the register contents immediately and then starts a new reading @@ -188,7 +191,7 @@ def get_sensor_readings(seconds_since_last, is_usb_power): bme280_data = bme280.read() ltr_data = ltr559.get_reading() - rain, rain_per_second = rainfall(seconds_since_last) + rain, rain_per_second, rain_per_hour, rain_today = rainfall(seconds_since_last) # Adjust pressure to calculated sea level value if set to in config pressure = bme280_data[1] / 100.0 @@ -203,6 +206,8 @@ def get_sensor_readings(seconds_since_last, is_usb_power): "wind_speed": wind_speed(), "rain": rain, "rain_per_second": rain_per_second, + "rain_per_hour": rain_per_hour, + "rain_today": rain_today, "wind_direction": wind_direction() }) diff --git a/enviro/helpers.py b/enviro/helpers.py index fb89f8c..3aa6587 100644 --- a/enviro/helpers.py +++ b/enviro/helpers.py @@ -24,6 +24,10 @@ def timestamp(dt): second = int(dt[17:19]) return time.mktime((year, month, day, hour, minute, second, 0, 0)) +def timestamp_day(dt): + day = int(dt[8:10]) + return day + def uid(): return "{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}".format(*machine.unique_id()) From a6665a9acc63d70aa40ca91107f29131462cdb2d Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Wed, 29 Mar 2023 23:14:39 +0100 Subject: [PATCH 12/25] Added rain per hour and day --- enviro/destinations/wunderground.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py index df7527e..7940747 100644 --- a/enviro/destinations/wunderground.py +++ b/enviro/destinations/wunderground.py @@ -2,7 +2,7 @@ from enviro.constants import UPLOAD_SUCCESS, UPLOAD_FAILED import urequests import config -from enviro.helpers import celcius_to_fahrenheit, hpa_to_inches, metres_per_second_to_miles_per_hour +from enviro.helpers import celcius_to_fahrenheit, hpa_to_inches, metres_per_second_to_miles_per_hour, mm_to_inches def log_destination(): logging.info(f"> uploading cached readings to Weather Underground device: {config.wunderground_id}") @@ -43,8 +43,13 @@ def upload_reading(reading): if key == "wind_direction": url += "&winddir=" + str(value) + if key == "rain_per_hour": + url += "&rainin=" + str(mm_to_inches(value)) + + if key == "rain_today": + url += "&dailyrainin=" + str(mm_to_inches(value)) + #TODO Potentially able to convert luminance to solar radiation (solarradiation - [W/m^2]) - #TODO Work out if the file in the rain trigger can be used to calculate and send (rainin - [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min) logging.info(f"> upload url: {url}") From e91ca6b16dd5b4e9d1f7c42520d467c49e7fe359 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Thu, 30 Mar 2023 18:11:43 +0100 Subject: [PATCH 13/25] Capture potential lost readings over midnight --- enviro/boards/weather.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index e9d3155..efab51a 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -165,6 +165,11 @@ def rainfall(seconds_since_last): # count how many rain ticks since the last reading if now - ts < seconds_since_last: amount += RAIN_MM_PER_TICK + # Pick up any untracked yesterday data if current reading is a new day + # Techincally this should be yesterday, but capturing in today is much + # less complex than backdating in the readings file from here + if tsday != now_day: + today += RAIN_MM_PER_TICK # count how many rain ticks in the last hour if now - ts < 3600: per_hour += RAIN_MM_PER_TICK From f7cc00534f683871a66ed0b5633879939812be45 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Thu, 30 Mar 2023 19:21:02 +0100 Subject: [PATCH 14/25] Add dewpoint calculation --- enviro/boards/weather.py | 8 +++++--- enviro/destinations/wunderground.py | 3 +++ enviro/helpers.py | 6 ++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index efab51a..ed6384e 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -198,14 +198,14 @@ def get_sensor_readings(seconds_since_last, is_usb_power): ltr_data = ltr559.get_reading() rain, rain_per_second, rain_per_hour, rain_today = rainfall(seconds_since_last) - # Adjust pressure to calculated sea level value if set to in config pressure = bme280_data[1] / 100.0 temperature = bme280_data[0] + humidity = bme280_data[2] from ucollections import OrderedDict readings = OrderedDict({ "temperature": round(temperature, 2), - "humidity": round(bme280_data[2], 2), + "humidity": round(humidity, 2), "pressure": round(pressure, 2), "luminance": round(ltr_data[BreakoutLTR559.LUX], 2), "wind_speed": wind_speed(), @@ -213,9 +213,11 @@ def get_sensor_readings(seconds_since_last, is_usb_power): "rain_per_second": rain_per_second, "rain_per_hour": rain_per_hour, "rain_today": rain_today, - "wind_direction": wind_direction() + "wind_direction": wind_direction(), + "dewpoint": round(helpers.calculate_dewpoint(temperature, humidity), 2) }) + # Add adjusted pressure to calculated sea level value if set to in config if config.sea_level_pressure: logging.info(f" - recorded temperature: {temperature}") logging.info(f" - recorded pressure: {pressure}") diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py index 7940747..16d16aa 100644 --- a/enviro/destinations/wunderground.py +++ b/enviro/destinations/wunderground.py @@ -49,6 +49,9 @@ def upload_reading(reading): if key == "rain_today": url += "&dailyrainin=" + str(mm_to_inches(value)) + if key == "dewpoint": + url += "&dewptf=" + str(celcius_to_fahrenheit(value)) + #TODO Potentially able to convert luminance to solar radiation (solarradiation - [W/m^2]) logging.info(f"> upload url: {url}") diff --git a/enviro/helpers.py b/enviro/helpers.py index 3aa6587..74e9a10 100644 --- a/enviro/helpers.py +++ b/enviro/helpers.py @@ -78,6 +78,12 @@ def absolute_to_relative_humidity(absolute_humidity, temperature_in_c): return (WATER_VAPOR_SPECIFIC_GAS_CONSTANT * temperature_in_k * absolute_humidity) / saturation_vapor_pressure * 100 +# https://www.omnicalculator.com/physics/dew-point#how-to-calculate-dew-point-how-to-calculate-relative-humidity +def calculate_dewpoint(temperature_in_c, relative_humidity): + alphatrh = (math.log((relative_humidity / 100))) + ((17.625 * temperature_in_c) / (243.04 + temperature_in_c)) + dewpoint_in_c = (243.04 * alphatrh) / (17.625 - alphatrh) + return dewpoint_in_c + def celcius_to_kelvin(temperature_in_c): return temperature_in_c + 273.15 From 5d9720288f8aa90b5424a144f3da41ce5a3aa4b0 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Thu, 30 Mar 2023 19:43:52 +0100 Subject: [PATCH 15/25] Can't measure radiation inside Stevenson screen --- enviro/destinations/wunderground.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py index 16d16aa..4a45db7 100644 --- a/enviro/destinations/wunderground.py +++ b/enviro/destinations/wunderground.py @@ -52,8 +52,6 @@ def upload_reading(reading): if key == "dewpoint": url += "&dewptf=" + str(celcius_to_fahrenheit(value)) - #TODO Potentially able to convert luminance to solar radiation (solarradiation - [W/m^2]) - logging.info(f"> upload url: {url}") try: From d988f87f057db19b2aac7a95c1e48254806f60a8 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 1 Apr 2023 14:10:23 +0100 Subject: [PATCH 16/25] Rain today adjusted to use local time --- enviro/boards/weather.py | 8 +++++--- enviro/config_defaults.py | 2 +- enviro/config_template.py | 3 +++ enviro/helpers.py | 11 ++++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index ed6384e..a3ab51e 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -1,4 +1,4 @@ -import time, math, os +import time, math, os, config from breakout_bme280 import BreakoutBME280 from breakout_ltr559 import BreakoutLTR559 from machine import Pin, PWM @@ -152,7 +152,8 @@ def rainfall(seconds_since_last): per_hour = 0 today = 0 now = helpers.timestamp(helpers.datetime_string()) - now_day = helpers.timestamp_day(helpers.datetime_string()) + now_day = helpers.timestamp_day(helpers.datetime_string(), config.utc_offset) + logging.info(f"> current day number is {now_day}") if helpers.file_exists("rain.txt"): with open("rain.txt", "r") as rainfile: rain_entries = rainfile.read().split("\n") @@ -161,7 +162,8 @@ def rainfall(seconds_since_last): for entry in rain_entries: if entry: ts = helpers.timestamp(entry) - tsday = helpers.timestamp_day(entry) + tsday = helpers.timestamp_day(entry, config.utc_offset) + logging.info(f"> rain reading day number is {tsday}") # count how many rain ticks since the last reading if now - ts < seconds_since_last: amount += RAIN_MM_PER_TICK diff --git a/enviro/config_defaults.py b/enviro/config_defaults.py index b29edc4..ea365ea 100644 --- a/enviro/config_defaults.py +++ b/enviro/config_defaults.py @@ -57,4 +57,4 @@ def add_missing_config_settings(): config.utc_offset = DEFAULT_UTC_OFFSET def warn_missing_config_setting(setting): - logging.warn(f"> config setting '{setting}' missing, please add it to config.py") + logging.warn(f"> config setting '{setting}' missing, please add it to config.py") \ No newline at end of file diff --git a/enviro/config_template.py b/enviro/config_template.py index fd27bd6..b301333 100644 --- a/enviro/config_template.py +++ b/enviro/config_template.py @@ -13,6 +13,9 @@ wifi_password = None wifi_country = "GB" +# For local time corrections to daily rain logging (include DST) +utc_offset = 1 + # how often to wake up and take a reading (in minutes) reading_frequency = 15 diff --git a/enviro/helpers.py b/enviro/helpers.py index 74e9a10..14252c0 100644 --- a/enviro/helpers.py +++ b/enviro/helpers.py @@ -1,5 +1,5 @@ from enviro.constants import * -import machine, math, os, time +import machine, math, os, time, utime # miscellany # =========================================================================== @@ -24,8 +24,13 @@ def timestamp(dt): second = int(dt[17:19]) return time.mktime((year, month, day, hour, minute, second, 0, 0)) -def timestamp_day(dt): - day = int(dt[8:10]) +# Return the day number of your timestamp string accommodating UTC offsets +def timestamp_day(dt, offset_hours): + # Bounce via timestamp to properly calculate hours change + time = timestamp(dt) + time = time + (offset_hours * 3600) + dt = utime.localtime(time) + day = int(dt[2]) return day def uid(): From 80bf616f16cf69309822c6f45a96608b229d51e1 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 1 Apr 2023 14:10:35 +0100 Subject: [PATCH 17/25] Updated documentation --- documentation/boards/enviro-weather.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/documentation/boards/enviro-weather.md b/documentation/boards/enviro-weather.md index 7b3866d..ce2d77c 100644 --- a/documentation/boards/enviro-weather.md +++ b/documentation/boards/enviro-weather.md @@ -13,11 +13,15 @@ Enviro Weather is a super slimline all in one board for keeping a (weather) eye |Air Pressure|`pressure`|hectopascals|hPa|`997.16`| |Luminance|`luminance`|lux|lx|`35`| |Rainfall|`rain`|millimetres|mm|`1.674`| -|Rainfall Average|`rain_per_second`|millimetres per second|mm/s|`1.674`| +|Rainfall Average Second|`rain_per_second`|millimetres per second|mm/s|`1.674`| +|Rainfall Average Hour|`rain_per_hour`|millimetres per hour|mm/h|`1.674`| +|Rainfall Today (local time)|`rain_today`|millimetres accumulated today|mm/s|`1.674`| |Wind Direction|`wind_direction`|angle|°|`45`| |Wind Speed|`wind_speed`|metres per second|m/s|`0.45`| |Voltage|`voltage`|volts|V|`4.035`| +The rain today value is adjusted for local time (and/or DST) by modifying the utc_offset value in config.py + ## On-board devices - BME280 temperature, pressure, humidity sensor. [View datasheet](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf) From 5513aa41b464e7e4531ea3acdecad936ec286750 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 1 Apr 2023 14:25:13 +0100 Subject: [PATCH 18/25] Documentation --- documentation/boards/enviro-weather.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/boards/enviro-weather.md b/documentation/boards/enviro-weather.md index ce2d77c..0531ac2 100644 --- a/documentation/boards/enviro-weather.md +++ b/documentation/boards/enviro-weather.md @@ -11,6 +11,7 @@ Enviro Weather is a super slimline all in one board for keeping a (weather) eye |Temperature|`temperature`|celcius|°C|`22.11`| |Humidity|`humidity`|percent|%|`55.42`| |Air Pressure|`pressure`|hectopascals|hPa|`997.16`| +|Adjusted Sea Level Air Pressure|`sea_level_pressure`|hectopascals|hPa|`1014.06`| |Luminance|`luminance`|lux|lx|`35`| |Rainfall|`rain`|millimetres|mm|`1.674`| |Rainfall Average Second|`rain_per_second`|millimetres per second|mm/s|`1.674`| From 045dbdbb308c612f14e922e963fc90cd653b7f05 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Sat, 1 Apr 2023 14:30:18 +0100 Subject: [PATCH 19/25] Documentation --- documentation/boards/enviro-weather.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/boards/enviro-weather.md b/documentation/boards/enviro-weather.md index 0531ac2..9437f34 100644 --- a/documentation/boards/enviro-weather.md +++ b/documentation/boards/enviro-weather.md @@ -10,6 +10,7 @@ Enviro Weather is a super slimline all in one board for keeping a (weather) eye |---|---|---|---|---| |Temperature|`temperature`|celcius|°C|`22.11`| |Humidity|`humidity`|percent|%|`55.42`| +|Dew Point|`dewpoint`|celcius|°C|`12.21`| |Air Pressure|`pressure`|hectopascals|hPa|`997.16`| |Adjusted Sea Level Air Pressure|`sea_level_pressure`|hectopascals|hPa|`1014.06`| |Luminance|`luminance`|lux|lx|`35`| From bfcc83d1996efc78cf38d4d007b8e07e2dc513cc Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Tue, 11 Apr 2023 19:03:46 +0100 Subject: [PATCH 20/25] Added request close --- enviro/destinations/wunderground.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enviro/destinations/wunderground.py b/enviro/destinations/wunderground.py index 4a45db7..6634ddf 100644 --- a/enviro/destinations/wunderground.py +++ b/enviro/destinations/wunderground.py @@ -58,7 +58,7 @@ def upload_reading(reading): # send (GET) reading data to http endpoint result = urequests.get(url) - logging.debug(f" - Result ({result.status_code} {result.reason})") + result.close() if result.status_code == 200: return UPLOAD_SUCCESS From 03dc23759ac01626278ada505033078ffdc407e6 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Thu, 13 Jul 2023 18:21:56 +0100 Subject: [PATCH 21/25] Add hard coded BST calculation for rain day --- enviro/boards/weather.py | 10 +++++++++- enviro/config_template.py | 8 ++++++-- enviro/helpers.py | 27 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index a3ab51e..bd1e0fb 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -151,8 +151,16 @@ def rainfall(seconds_since_last): amount = 0 per_hour = 0 today = 0 + offset = 0 + + if config.uk_bst == True: + if helpers.uk_bst(): + offset = 1 + elif config.utc_offset != 0: + offset += config.utc_offset + now = helpers.timestamp(helpers.datetime_string()) - now_day = helpers.timestamp_day(helpers.datetime_string(), config.utc_offset) + now_day = helpers.timestamp_day(helpers.datetime_string(), offset) logging.info(f"> current day number is {now_day}") if helpers.file_exists("rain.txt"): with open("rain.txt", "r") as rainfile: diff --git a/enviro/config_template.py b/enviro/config_template.py index b301333..aa29b18 100644 --- a/enviro/config_template.py +++ b/enviro/config_template.py @@ -13,8 +13,12 @@ wifi_password = None wifi_country = "GB" -# For local time corrections to daily rain logging (include DST) -utc_offset = 1 +# Adjust daily rain day for UK BST +uk_bst = True + +# For local time corrections to daily rain logging other than BST +# Ignored if uk_bst = True +utc_offset = 0 # how often to wake up and take a reading (in minutes) reading_frequency = 15 diff --git a/enviro/helpers.py b/enviro/helpers.py index 14252c0..feb85f5 100644 --- a/enviro/helpers.py +++ b/enviro/helpers.py @@ -1,5 +1,6 @@ from enviro.constants import * import machine, math, os, time, utime +from phew import logging # miscellany # =========================================================================== @@ -24,6 +25,32 @@ def timestamp(dt): second = int(dt[17:19]) return time.mktime((year, month, day, hour, minute, second, 0, 0)) +def uk_bst(): + # Return True if in UK BST - manually update bst_timestamps {} as needed + dt = datetime_string() + year = int(dt[0:4]) + ts = timestamp(dt) + bst = False + + bst_timestamps = { + 2023: {"start": 1679792400, "end": 1698541200}, + 2024: {"start": 1711846800, "end": 1729990800}, + 2025: {"start": 1743296400, "end": 1761440400}, + 2026: {"start": 1774746000, "end": 1792890000}, + 2027: {"start": 1806195600, "end": 1824944400}, + 2028: {"start": 1837645200, "end": 1856394000}, + 2029: {"start": 1869094800, "end": 1887843600}, + 2030: {"start": 1901149200, "end": 1919293200} + } + + if year in bst_timestamps: + if bst_timestamps[year]["start"] < ts and bst_timestamps[year]["end"] > ts: + bst = True + else: + logging.warn(f"> Provided year is not in BST lookup dictionary: {year}") + return bst + + # Return the day number of your timestamp string accommodating UTC offsets def timestamp_day(dt, offset_hours): # Bounce via timestamp to properly calculate hours change From 2baf04ed29351b81f182089b8eea763d635a4687 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Tue, 29 Aug 2023 14:08:40 +0100 Subject: [PATCH 22/25] Documentation update for uk_bst --- documentation/boards/enviro-weather.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/boards/enviro-weather.md b/documentation/boards/enviro-weather.md index 9437f34..f654ba2 100644 --- a/documentation/boards/enviro-weather.md +++ b/documentation/boards/enviro-weather.md @@ -22,7 +22,9 @@ Enviro Weather is a super slimline all in one board for keeping a (weather) eye |Wind Speed|`wind_speed`|metres per second|m/s|`0.45`| |Voltage|`voltage`|volts|V|`4.035`| -The rain today value is adjusted for local time (and/or DST) by modifying the utc_offset value in config.py +The rain today value is adjusted for DST in the UK by setting uk_bst = True in config.py +For static time zone offsets (not taking account of DST), modify the utc_offset value in config.py +The time zone offset value is ignored if uk_bst = True ## On-board devices From 0210499aa5805c5b8e44bcb2646fc3f5d70aace0 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Tue, 29 Aug 2023 14:26:52 +0100 Subject: [PATCH 23/25] Log message improvement --- enviro/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enviro/helpers.py b/enviro/helpers.py index feb85f5..30b08cb 100644 --- a/enviro/helpers.py +++ b/enviro/helpers.py @@ -47,7 +47,7 @@ def uk_bst(): if bst_timestamps[year]["start"] < ts and bst_timestamps[year]["end"] > ts: bst = True else: - logging.warn(f"> Provided year is not in BST lookup dictionary: {year}") + logging.warn(f"> Current year is not in BST lookup dictionary: {year}") return bst From 34504bb084229bda3e62b4eb67450f238439f072 Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Tue, 29 Aug 2023 14:57:02 +0100 Subject: [PATCH 24/25] Improved comments --- enviro/boards/weather.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/enviro/boards/weather.py b/enviro/boards/weather.py index bd1e0fb..5eeb74c 100644 --- a/enviro/boards/weather.py +++ b/enviro/boards/weather.py @@ -148,47 +148,56 @@ def wind_direction(): def rainfall(seconds_since_last): new_rain_entries = [] - amount = 0 + amount = 0 # rain since last reading per_hour = 0 today = 0 - offset = 0 + offset = 0 # UTC offset hours + # configure offset variable for UK BST or timezone offset from config file + # and BST lookup function if config.uk_bst == True: if helpers.uk_bst(): offset = 1 elif config.utc_offset != 0: offset += config.utc_offset + # determine current day number and timestamp now = helpers.timestamp(helpers.datetime_string()) now_day = helpers.timestamp_day(helpers.datetime_string(), offset) logging.info(f"> current day number is {now_day}") + + # process the rain file data if helpers.file_exists("rain.txt"): with open("rain.txt", "r") as rainfile: rain_entries = rainfile.read().split("\n") - # process the rain file data + # populate latest, per second, today and last hour readings from rain log + # file, write new rain log file dropping any yesterday readings for entry in rain_entries: if entry: ts = helpers.timestamp(entry) tsday = helpers.timestamp_day(entry, config.utc_offset) logging.info(f"> rain reading day number is {tsday}") - # count how many rain ticks since the last reading + # populate amount with rain since the last reading if now - ts < seconds_since_last: amount += RAIN_MM_PER_TICK - # Pick up any untracked yesterday data if current reading is a new day - # Techincally this should be yesterday, but capturing in today is much - # less complex than backdating in the readings file from here + # add any rain ticks from yesterday since the previous reading + # this will misallocate day totals, but will ensure the hourly total + # is correct without introducing complexity backdating yesterday and + # the error will be minimised with frequent readings + # TODO sum yesterday rain and generate a rain_today reading with + # 23:59:59 timestamp of yesterday if tsday != now_day: today += RAIN_MM_PER_TICK # count how many rain ticks in the last hour if now - ts < 3600: per_hour += RAIN_MM_PER_TICK - # count how many rain ticks today and delete older entries + # count how many rain ticks today and drop older entries for new file if tsday == now_day: today += RAIN_MM_PER_TICK new_rain_entries.append(entry) - # write out adjusted rain log + # write out new adjusted rain log with open("rain.txt", "w") as newrainfile: newrainfile.write("\n".join(new_rain_entries)) From 41ee5b6292db36c2fe8d06b23a4d24dc98163c8b Mon Sep 17 00:00:00 2001 From: Stephen Jefferson Date: Thu, 25 Apr 2024 19:38:23 +0100 Subject: [PATCH 25/25] Re add missed wifi_country from merge conflict --- enviro/config_defaults.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/enviro/config_defaults.py b/enviro/config_defaults.py index ea365ea..0c0cbbf 100644 --- a/enviro/config_defaults.py +++ b/enviro/config_defaults.py @@ -20,6 +20,12 @@ def add_missing_config_settings(): warn_missing_config_setting("usb_power_temperature_offset") config.usb_power_temperature_offset = DEFAULT_USB_POWER_TEMPERATURE_OFFSET + try: + config.wifi_country + except AttributeError: + warn_missing_config_setting("wifi_country") + config.wifi_country = "GB" + try: config.wunderground_id except AttributeError: