Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust temperature under usb power #142

Merged
merged 22 commits into from
Feb 12, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions enviro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,11 @@ def sleep(time_override=None):
rtc.set_alarm(0, minute, hour)
rtc.enable_alarm_interrupt(True)

# assume we're running on battery power
logging.debug("assume battery power in config")
config.usb_power = False
helpers.write_config(config)

# disable the vsys hold, causing us to turn off
logging.info(" - shutting down")
hold_vsys_en_pin.init(Pin.IN)
Expand All @@ -477,6 +482,12 @@ def sleep(time_override=None):
# case we can't (and don't need to) sleep.
stop_activity_led()

# indicate that we're running on usb power - which requires temperature
# and humidity adjustments.
logging.debug("switching config to usb power")
config.usb_power = True
helpers.write_config(config)

# if running via mpremote/pyboard.py with a remote mount then we can't
# reset the board so just exist
if phew.remote_mount:
Expand Down
15 changes: 13 additions & 2 deletions enviro/boards/indoor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import enviro.helpers as helpers
import math
from breakout_bme68x import BreakoutBME68X
from breakout_bh1745 import BreakoutBH1745

from enviro import config
from enviro import i2c

bme688 = BreakoutBME68X(i2c, address=0x77)
Expand Down Expand Up @@ -44,8 +46,17 @@ def get_sensor_readings(seconds_since_last):
data = bme688.read()

temperature = round(data[0], 2)
pressure = round(data[1] / 100.0, 2)
humidity = round(data[2], 2)

# Compensate for additional heating when on usb power - this also changes the
# relative humidity value.
if config.usb_power:
adjusted_temperature = temperature - config.usb_power_temperature_offset
macifell marked this conversation as resolved.
Show resolved Hide resolved
absolute_humidity = helpers.relative_to_absolute_humidity(humidity, temperature)
humidity = helpers.absolute_to_relative_humidity(absolute_humidity, adjusted_temperature)
temperature = adjusted_temperature

pressure = round(data[1] / 100.0, 2)
gas_resistance = round(data[3])
# an approximate air quality calculation that accounts for the effect of
# humidity on the gas sensor
Expand All @@ -64,4 +75,4 @@ def get_sensor_readings(seconds_since_last):
"aqi": aqi,
"luminance": lux_from_rgbc(r, g, b, c),
"color_temperature": colour_temperature_from_rgbc(r, g, b, c)
})
})
6 changes: 5 additions & 1 deletion enviro/config_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,8 @@
auto_water = False
moisture_target_a = 50
moisture_target_b = 50
moisture_target_c = 50
moisture_target_c = 50

# compensate for usb power
usb_power = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usb_power should not be in config.py. See comments within PR

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense. This started out with the intent that the user would set this, but then I wanted to see if I could change it automatically 🙂

usb_power_temperature_offset = 4
5 changes: 5 additions & 0 deletions enviro/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@
UPLOAD_SUCCESS = 0
UPLOAD_FAILED = 1
UPLOAD_RATE_LIMITED = 2

# humidity
WATER_VAPOR_SPECIFIC_GAS_CONSTANT = 461.5
CRITICAL_WATER_TEMPERATURE = 647.096
CRITICAL_WATER_PRESSURE = 22064000
60 changes: 59 additions & 1 deletion enviro/helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from enviro.constants import *
import machine, os, time
import machine, math, os, time

# miscellany
# ===========================================================================
Expand Down Expand Up @@ -57,3 +57,61 @@ def copy_file(source, target):
if not chunk:
break
outfile.write(chunk)

def write_config(config):
lines = []
with open("config.py", "r") as infile:
lines = infile.read().split("\n")

for i in range(0, len(lines)):
line = lines[i]
parts = line.split("=", 1)
if len(parts) == 2:
key = parts[0].strip()
if hasattr(config, key):
value = getattr(config, key)
lines[i] = f"{key} = {repr(value)}"

with open("config.py", "w") as outfile:
outfile.write("\n".join(lines))

# temperature and humidity helpers
# ===========================================================================

# https://www.calctool.org/atmospheric-thermodynamics/absolute-humidity#what-is-and-how-to-calculate-absolute-humidity
def relative_to_absolute_humidity(relative_humidity, temperature_in_c):
temperature_in_k = celcius_to_kelvin(temperature_in_c)
actual_vapor_pressure = get_actual_vapor_pressure(relative_humidity, temperature_in_k)

return actual_vapor_pressure / (WATER_VAPOR_SPECIFIC_GAS_CONSTANT * temperature_in_k)

def absolute_to_relative_humidity(absolute_humidity, temperature_in_c):
temperature_in_k = celcius_to_kelvin(temperature_in_c)
saturation_vapor_pressure = get_saturation_vapor_pressure(temperature_in_k)

return (WATER_VAPOR_SPECIFIC_GAS_CONSTANT * temperature_in_k * absolute_humidity) / saturation_vapor_pressure * 100

def celcius_to_kelvin(temperature_in_c):
return temperature_in_c + 273.15

# 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):
return get_saturation_vapor_pressure(temperature_in_k) * (relative_humidity / 100)

def get_saturation_vapor_pressure(temperature_in_k):
v = 1 - (temperature_in_k / CRITICAL_WATER_TEMPERATURE)

# empirical constants
a1 = -7.85951783
a2 = 1.84408259
a3 = -11.7866497
a4 = 22.6807411
a5 = -15.9618719
a6 = 1.80122502

return CRITICAL_WATER_PRESSURE * math.exp(
CRITICAL_WATER_TEMPERATURE /
temperature_in_k *
(a1*v + a2*v**1.5 + a3*v**3 + a4*v**3.5 + a5*v**4 + a6*v**7.5)
)
32 changes: 7 additions & 25 deletions enviro/provisioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,6 @@
if not helpers.file_exists("config.py"):
helpers.copy_file("enviro/config_template.py", "config.py")

# write the current values in config to the config.py file
def write_config():
lines = []
with open("config.py", "r") as infile:
lines = infile.read().split("\n")

for i in range(0, len(lines)):
line = lines[i]
parts = line.split("=", 1)
if len(parts) == 2:
key = parts[0].strip()
if hasattr(config, key):
value = getattr(config, key)
lines[i] = f"{key} = {repr(value)}"

with open("config.py", "w") as outfile:
outfile.write("\n".join(lines))

import config


Expand Down Expand Up @@ -71,7 +53,7 @@ def provision_welcome(request):
def provision_step_1_nickname(request):
if request.method == "POST":
config.nickname = request.form["nickname"]
write_config()
helpers.write_config(config)
return redirect(f"http://{DOMAIN}/provision-step-2-wifi")
else:
return render_template("enviro/html/provision-step-1-nickname.html", board=model)
Expand All @@ -82,7 +64,7 @@ def provision_step_2_wifi(request):
if request.method == "POST":
config.wifi_ssid = request.form["wifi_ssid"]
config.wifi_password = request.form["wifi_password"]
write_config()
helpers.write_config(config)
return redirect(f"http://{DOMAIN}/provision-step-3-logging")
else:
return render_template("enviro/html/provision-step-2-wifi.html", board=model)
Expand All @@ -93,7 +75,7 @@ def provision_step_3_logging(request):
if request.method == "POST":
config.reading_frequency = int(request.form["reading_frequency"])
config.upload_frequency = int(request.form["upload_frequency"]) if request.form["upload_frequency"] else None
write_config()
helpers.write_config(config)
return redirect(f"http://{DOMAIN}/provision-step-4-destination")
else:
return render_template("enviro/html/provision-step-3-logging.html", board=model)
Expand Down Expand Up @@ -124,7 +106,7 @@ def provision_step_4_destination(request):
config.influxdb_token = request.form["influxdb_token"]
config.influxdb_bucket = request.form["influxdb_bucket"]

write_config()
helpers.write_config(config)

if model == "grow":
return redirect(f"http://{DOMAIN}/provision-step-grow-sensors")
Expand Down Expand Up @@ -153,7 +135,7 @@ def provision_step_grow_sensors(request):
except ValueError:
pass

write_config()
helpers.write_config(config)

return redirect(f"http://{DOMAIN}/provision-step-5-done")
else:
Expand All @@ -163,7 +145,7 @@ def provision_step_grow_sensors(request):
@server.route("/provision-step-5-done", methods=["GET", "POST"])
def provision_step_5_done(request):
config.provisioned = True
write_config()
helpers.write_config(config)

# a post request to the done handler means we're finished and
# should reset the board
Expand Down Expand Up @@ -207,4 +189,4 @@ def catchall(request):
logging.info(" - client connected!", ap.status("stations")[0])

logging.info("> running provisioning application...")
server.run(host="0.0.0.0", port=80)
server.run(host="0.0.0.0", port=80)
macifell marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@
# here you can customise the sensor readings by adding extra information
# or removing readings that you don't want, for example:
#
# del readings["temperature"] # remove the temperature reading
# del reading["temperature"] # remove the temperature reading
macifell marked this conversation as resolved.
Show resolved Hide resolved
#
# readings["custom"] = my_reading() # add my custom reading value
# reading["custom"] = my_reading() # add my custom reading value

# is an upload destination set?
if enviro.config.destination:
Expand Down