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.