diff --git a/README.md b/README.md index 7a33e22..e5f92c4 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ -# pico-dht22 +# PicoW DHT22 +> PicoW with DHT22 attached. -A small python project to use MicroPython on a Pico W with a DHT22 sensor to publish a climate data to MQTT broker. +#### Features: +- Measure current temperature & humidity with DHT22 Sensor +- Measure & Report VSYS +- Measure & Report CPU Temp + +### Use +- Upload files onto PICO, adjust params (such as Wi-Fi Credentials // pins // etc ), deploy to your PICO W diff --git a/main.py b/main.py new file mode 100644 index 0000000..b438590 --- /dev/null +++ b/main.py @@ -0,0 +1,208 @@ +import network +import rp2 +import time +import machine +from machine import Pin +import dht +import urequests +import wifi_config + +# Change this GPIO PIN where your DHT22 sensor is connected +DHT_22_GPIO_PIN = 2 + +def read_cpu_temp(): + """ + If you print the value of the temperature value you are going to get an integer number between 0 and 65535. + So, we have to convert this value either to the Celsius degree scales. + + The temperature sensor works by delivering a voltage to the ADC4 pin that is proportional to the temperature. + From the datasheet, a temperature of 27 degrees Celsius delivers a voltage of 0.706 V. + With each additional degree the voltage reduces by 1.721 mV or 0.001721 V. + The first step in converting the 16-bit temperature is to convert it back to volts, which is done based on the 3.3 V maximum voltage used by the Pico board. + ref: https://how2electronics.com/read-temperature-sensor-value-from-raspberry-pi-pico/ + """ + cpu_temp_conversion_factor = 3.3 / 65535 + cpu_temp_sensor = machine.ADC(4) + reading = cpu_temp_sensor.read_u16() * cpu_temp_conversion_factor + temperature_c = 27 - (reading - 0.706) / 0.001721 + temperature_f = temperature_c * 9/5. + 32 + return temperature_f + +def read_vsys(): + # Set pin 29 for the voltage reading + # Note, this will break Wi-Fi until the pin is set back to original state + # See lines below where the state is reset + Pin(29, Pin.IN) + Vsys = machine.ADC(3) + conversion_factor = 3.3 * 3 / 65535 + reading = Vsys.read_u16() * conversion_factor + + # Reset pin back to the original state + # This original state is found by printing the value of the pin at the start of this function + # alt=7 seems to be Wi-Fi related, so + Pin(29, Pin.ALT, Pin.PULL_DOWN, alt=7) + + return reading + +def read_dht_22_raw(sensor): + """ + reads the temperature and humidity from dht.DHT22 sensor. + returns tuple(temperature, humidity) if no errors + returns None if there was an error + """ + try: + sensor.measure() + temperature = sensor.temperature() + humidity = sensor.humidity() + return temperature, humidity + except OSError: + return None + +def read_dht_22_with_retry(sensor): + """Same as [read_dht_22_raw] but tries a few times before giving up. Same returns as [read_dht_22_raw]""" + count = 0 + while count < 2: + reading = read_dht_22_raw(sensor) + count += 1 + if reading is not None: + return reading + time.sleep(2) + return None + +def read_dht_22(sensor): + """ + When DHT22 runs on 3.3v sometimes the output results are incomplete, at least what I've seen before + i.e it can return 2deg, 0deg for a measurement, and the normal readings + This is a hack to see if this solves this problem, we take 2 measurements and if they are not same (or close), discard + """ + reading_1 = read_dht_22_with_retry(sensor) + + if reading_1 is None: + print("read_dht_22, reading 1 is None. Abort") + return None + # print("Reading 1: {}".format(reading_1)) + + time.sleep(2) + + reading_2 = read_dht_22_with_retry(sensor) + + if reading_2 is None: + print("read_dht_22, reading 2 is None. Abort") + return None + + # print("Reading 2: {}".format(reading_2)) + + diff = abs(reading_1[0] - reading_2[0]) + #print("Reading between 1 and 2 is {}".format(diff)) + if diff > 2: + print("Reading between 1 and 2 is more than 2 deg apart, {}".format(diff)) + return None + + return reading_1 + +def wlan_up(wlan): + print("Connecting to Wifi...") + wlan.active(True) + print("Wifi chip is active ... wlan.connect now") + wlan.connect(wifi_config.HOME_WIFI_SSID, wifi_config.HOME_WIFI_PWD) + print("wlan.connect is done") + + # Wait for connect or fail + max_wait = 10 + while max_wait > 0: + if wlan.status() < 0 or wlan.status() >= 3: + break + max_wait -= 1 + print('waiting for connection...') + time.sleep(1) + + if wlan.status() != 3: + raise RuntimeError('network connection failed, {}'.format(wlan.status())) + + ifconfig = wlan.ifconfig() + print(ifconfig) + print("Connected to Wifi") + return ifconfig + +def led_error_code(led, error_code: int): + """Blink LED for a given error code (int). error code == number of times to blink""" + print("LED Error Status code: {}".format(error_code)) + + # Run a quick 'start error code sequence' + # So we know when LED error sequence starts + start_sequence_counter = 0 + while start_sequence_counter < 3: + led.value(True) + time.sleep(0.1) + led.value(False) + time.sleep(0.1) + start_sequence_counter += 1 + + # Run real error code sequence + blink_counter = 0 + while blink_counter < error_code: + time.sleep(1) + led.value(True) + time.sleep(1) + led.value(False) + blink_counter += 1 + # Make sure to turn off LED when this subroutine finished + led.value(False) + print("LED Error Status code finished for: {}".format(error_code)) + + +def main(): + print("Start up") + + # Set Wi-Fi Country + rp2.country('US') + wlan = network.WLAN(network.STA_IF) + + sensor = dht.DHT22(Pin(DHT_22_GPIO_PIN)) + + led = machine.Pin('LED', machine.Pin.OUT) + led.value(False) + + led_error_code(led, 1) + + print("Enter main loop") + + while True: + led.value(False) + # Read vsys before doing any WiFi connections makes the board more stable over long runs + vsys_volts = read_vsys() + try: + ifconfig = wlan_up(wlan) + except Exception as e: + print("Trouble to connecting WiFi: {}".format(e)) + # Should we raise a problem vs just try it again ? + # raise RuntimeError('Trouble to connecting WiFi, {}'.format(e)) + led_error_code(led, 3) + continue + + dht22_reading = read_dht_22(sensor) + + debug_str = "None" + if dht22_reading is not None: + temp,hum = dht22_reading + temp = temp * 9/5. + 32 # Convert to degF + print("DHT22 Temp: {} ; DHT22 Humidity: {}".format(temp, hum)) + + cpu_temp = read_cpu_temp() + + print("{} ; CPU: {} ; Vsys: {}".format(debug_str, cpu_temp, vsys_volts)) + + print("Going sleep ...\n\n") + time.sleep(10) + + # Prep HW for sleep + #wlan.disconnect() + #wlan.active(False) + #wlan.deinit() + #machine.lightsleep(10) + #print("Woke up ...") + + + +print('Start/Woke, reset clause {}'.format(machine.reset_cause())) +main()