I’m teaching an ESP32 IoT course in both Korean and English. The textbook includes a link to purchase an ESP32 Board with 8 shields and various sensors.
Problem
The author’s code references several different sensors with non-standardized code. Although there is a Parse class to extract JSON data from the various sensors, using non-standardized code means that there are many if-else blocks needed to _arrange_data() properly.
For example, the sensor_dictionary.py provides JSON data like this:
# gpio에 연결
value_dht22 = {
'DHT22': {
'Temperature': 23.5,
'Humidity': 45
},
'TempUnit': 'C'
}
# OnwWire에 여러 개의 센서 연결
value_ds18b20 = {
'DS18B20_1': {
'Temperature': 20.5,
'Humidity': 54
},
'DS18B20_2': {
'Temperature': 25.5,
'Humidity': 50
},
'TempUnit': 'C'
}
# I2C에 연결
value_bh1750 = {
'BH1750': {
'Brightness': 55
}
}
An example of parsing the DHT22 Sensor data can be seen below, and the full parse.py code is available online:
def main():
import pinno as P
from parse import Parse
sensor = DHT22Sensor(P.DHT, ser="001") # 예시로 "001"을 ser에 입력
while True:
data = sensor.read()
print(data)
p = Parse(data)
print(f'name: {p.name}, {p.keys[0]}: {p.values[0]}, {p.keys[1]}: {p.values[1]}, TempUnit: {p.temp_unit}')
time.sleep_ms(5000)
This code will work as is, but it has problems:
- Sensor names always are expected to be top-level keys
TempUnitis special-cased- OneWire and DS18B20 get special variables:
ow_id,ow_keys,ow_values - It does not nautrally support per-value units
- It makes it more difficult to standardize and use with:
- MQTT
- JSON uploads
- Node-RED
- ThinkSpeak
- Other platforms that process JSON data
Solution
Therefore, I have created a better_parse.py file that parses data from standardized JSON formatted sensor files. This will keep the sensor data much closer to a real IoT payload.
For example:
data = {
"sensor": "temperature",
"values": {
"current": 22.5,
"min": 18.0,
"max": 25.0
},
"unit": {
"current": "°C",
"min": "°C",
"max": "°C"
},
"timestamp": 1625247600
}
parse = Parse(data)
print(parse.name) # Output: temperature
print(parse.get("current")) # Output: 22.5
print(parse.get_unit("current")) # Output: °C
This generic sensor parser is better for the following reasons:
- It works with ANY sensor that follows the same JSON stucture
- It works with all existing sensors (if the JSON structure is updated), and any future sensors that may be added
- It works for single-value and multi-value sensors
- It uses a consistent parsing API, and dynamically extracts:
sensorname- keys
valuesunits- metadata
Updating all of the above sensor data to the new standardized format looks like this:
sensors = [
{
"sensor": "DHT22",
"values": {
"Temperature": 25.6,
"Humidity": 45
},
"units": {
"Temperature": "C",
"Humidity": "%"
},
"timestamp": 123456789
},
{
"sensor": "BH1750",
"values": {
"Lux": 352
},
"units": {
"Lux": "lx"
},
"timestamp": 123456789
},
{
"sensor": "DS18B20",
"values": {
"Temperature": 24.1
},
"units": {
"Temperature": "C"
},
"timestamp": 123456789
}
]
Now we can use the same format for every sensor and a single, simpler, parse.py file to extract the data. This will make collecting data from our IoT devices much simpler. It will also future-proof our code so that we can add any number of extra sensors in the future without drastically updating the code.