In case you are a nut case and want everything monitored and under control, as I do, you NEED a temperature and humidity monitoring device that is at least semi-reliable, throwable, checkable, cheap and ugly as fuck.
Also, the results can be seen here: https://bastart.spoton.cz/temphumi/ and especially, the graphing for battery state (3rd graph from top): https://bastart.spoton.cz/status/
Search no more, as you have found it, read on and relive the ecstatic feelings of designing an ass-ripping ultra portable ESP8266 powered temperhumi meter for a couple [f|b]ucks.
Da parts.
When it comes to hardware selection, it was an obvious choice. What better a device to find than an ESP8266-12F in it’s all bare guts sticking out. The DHT11 is very inprecise, but cheap and easy to work with. Also, with every unit manufactured – a polar bear dies. Go get ’em. For the other stuff, a few capacitors, some resistors etc…
Heck, I shall put a list of all that shit for this MOFO project just here:
- ESP8266-12E/F
- DHT11, or even the more advanced DHT22 would work, I assume
- battery case for 3x AAA sized batteries (1.2V NiMh preferred)
- self-made PCB – more on that later
- 2x10k, 1x2k7 resistors
- 1x 100nF, 1x10uF capacitors
- couple pin headers, if you want to have it fancy (DIN 2.54mm)
- want a case? Get a case then
Da code.
As nobody cares about the hardware part, let’s look at the software part. My choice of language to fit this non-demanding and stupidly ugly project – YEAH! Python. Micro Python that is, as this small thing runs on these small things (i.e. uPython runs on ESP8266). No interrupts, no memory allocations, nothing of the stuff that grown-ups do with microprocessors.
Alright, alright, you expect a chunk of code, copy paste it and move on. Well, here you go then. **slab**
import dht
import machine
import utime
import urequests
import network
import json
import esp
from flashbdev import bdev
"""
Variables
--------------------------------------------------------------------------------
"""
# Do we want to measure internal or external? VCC / ADC
ADC_MODE_VCC = 255
ADC_MODE_ADC = 0
# Network credentials pulled from inet.conf residing on the FS
# options check
possible_opts = ['ssid', 'pass', 'ip', 'netmask', 'gw', 'destination', 'dns']
# Let's set location, will be set as a tag in influx
_LOCATION_TYPE = "Tea"
# INFLUX config - can be part of the config file, no?
_INFLUX_HOST = '192.168.8.15'
_INFLUX_PORT = '8086'
_INFLUX_DB = 'indb'
_INFLUX_USER = 'pi'
_INFLUX_PASS = 'password'
"""
Functions
--------------------------------------------------------------------------------
"""
def set_adc_mode(mode):
# Switch between internal and external ADC. Returns if restart is needed
# Mode up in variables
sector_size = bdev.SEC_SIZE
flash_size = esp.flash_size() # device dependent
init_sector = int(flash_size / sector_size - 4)
data = bytearray(esp.flash_read(init_sector * sector_size, sector_size))
if data[107] == mode:
# flash is already correct; nothing to do
return False
else:
data[107] = mode # re-write flash
esp.flash_erase(init_sector)
esp.flash_write(init_sector * sector_size, data)
print("ADC mode changed in flash; restart to use it!")
return True
def check_wake_state():
# check if the device woke from a deep sleep
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
print('woke from a deep sleep')
else:
print(machine.reset_cause())
utime.sleep_ms(10)
def deep_sleep(sleep_minutes):
sleep_ms = sleep_minutes * 60 * 1000
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)
rtc.alarm(rtc.ALARM0, sleep_ms)
machine.deepsleep()
def read_network_config():
config_dict = {}
try:
with open('inet.conf', 'r') as conf_handler:
config = conf_handler.readlines()
for item in config:
tmp_list = item.split("=")
option = tmp_list[0].strip()
if len(tmp_list) == 2 and option in possible_opts:
value = tmp_list[1].strip()
config_dict.update({option: value})
else:
pass
except Exception as e:
print("WARNING: Errors in INFRA config, still going for AP")
return False
print(config_dict)
return config_dict
def set_up_infra(_SSID, _PASS, _TIMEOUT):
sta = network.WLAN(network.STA_IF)
ap = network.WLAN(network.AP_IF)
print("Disabling AP")
ap.active(False)
print("Activating INFRA")
sta.active(True)
sta.isconnected() # False, it should be # Comments by Yoda
print("Connecting to infra")
sta.connect(_SSID, _PASS)
connection_tout = _TIMEOUT
print("Let's wait for the network to come up") # Hopefully not indefinitely
# That's why we have a nice timeout, so it does not drain the batt on con
while not (sta.isconnected()):
if connection_tout > 0:
print("Trying... {} more times".format(connection_tout))
utime.sleep_ms(500)
connection_tout = connection_tout - 1
else:
print("Out of retrys while waiting for network, going to sleep")
utime.sleep_ms(500)
return False
network_config = sta.ifconfig()
return network_config
"""
Network configuration section
--------------------------------------------------------------------------------
"""
try:
net_config = read_network_config()
if net_config:
net_conf_result = set_up_infra(net_config["ssid"],
net_config["pass"],
10)
else:
print("ERROR: cannot read from inet.conf file")
utime.sleep_ms(100)
if net_conf_result:
print("Connected:")
print(" IP: {}".format(net_conf_result[0]))
print(" MASK: {}".format(net_conf_result[1]))
print(" GW: {}".format(net_conf_result[2]))
print(" DNS: {}\n".format(net_conf_result[3]))
else:
print("WARNING: Network config not done")
except Exception as e:
print("ERROR: Network configuration failed with: {}".format(e))
print("Network section done")
"""
Measure temperhumi
--------------------------------------------------------------------------------
"""
print("getting the temperature here")
d1 = machine.Pin(5, machine.Pin.IN)
try:
local_dht = dht.DHT11(d1)
local_dht.measure()
temperature = local_dht.temperature()
humidity = local_dht.humidity()
print("T: {}".format(temperature))
print("H: {}".format(humidity))
except Exception as e:
print("ERROR: Temp measurement: {}".format(e))
temperature = 255
humidity = 255
"""
Measure battery
--------------------------------------------------------------------------------
"""
print("Setting ADC mode here")
set_adc_mode(ADC_MODE_VCC)
vcc = machine.ADC(1)
val = vcc.read()
utime.sleep(2)
battery = vcc.read()
"""
Data send
--------------------------------------------------------------------------------
"""
if net_conf_result:
post_str = "http://{}:{}/write?db={}&u={}&p={}"
post = post_str.format(_INFLUX_HOST,
_INFLUX_PORT,
_INFLUX_DB,
_INFLUX_USER,
_INFLUX_PASS)
data_str = "usense,type={_type} humidity={_humi} \n " + \
"usense,type={_type} temperature={_temp}\n " + \
"usense,type={_type} battery={_batt}"
data = data_str.format(_type=_LOCATION_TYPE,
_humi=humidity,
_temp=temperature,
_batt=battery)
print(data)
try:
result = urequests.post(post, data=data)
except Exception as e:
print("ERROR: Data send 'urequest': {}".format(e))
# Go to sleep, cause why the fuck not
deep_sleep(28)
print(result.text)
else:
print("WARNING: Not sending data, as infra is not available")
# Sleep, deep. You earned it
deep_sleep(28)
So you want a better guide to the hardware part, eh? Wait for it and hold my beer…
How to put it together
You might want to read a couple articles first. namely http://wp.spoton.cz/2017/11/21/bricking-and-flashing-esp-01s-8266/ to see how to flash an ESP and http://wp.spoton.cz/2017/11/29/micropython-on-esp-01-8266/ on how to setup micropython on an ESP.