Skip to content

Commit

Permalink
Add Input: Generic TH10/16 for any Temp/Hum sensor
Browse files Browse the repository at this point in the history
  • Loading branch information
kizniche committed Dec 4, 2021
1 parent d2f9dbc commit 4cdf5b5
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -18,6 +18,7 @@
- Add Input: HTU21D Variant using the CircuitPython library
- Add Input: SCD-4x (40, 41) CO2/Temp/Hum sensor
- Add Input: Si7021 Temp/Hum sensor
- Add Input: Generic TH10/16 for any Temp/Hum sensor
- Add PWM Output option: Invert Stored Signal

### Miscellaneous
Expand Down
2 changes: 1 addition & 1 deletion mycodo/inputs/ads1115_circuitpython.py
Expand Up @@ -81,7 +81,7 @@ def constraints_pass_measurement_repetitions(mod_input, value):
'name': lazy_gettext('Measurements to Average'),
'phrase': lazy_gettext(
'The number of times to measure each channel. An average of the measurements will be stored.')
},
}
]
}

Expand Down
133 changes: 133 additions & 0 deletions mycodo/inputs/th1x.py
@@ -0,0 +1,133 @@
# coding=utf-8
# Input module for Sonoff TH16 or TH10.
# Requires Tasmota firmware flashed to the Sonoff's ESP8266
# https://github.com/arendst/Sonoff-Tasmota
import datetime
import json

import copy
import requests
from flask_babel import lazy_gettext

from mycodo.inputs.base_input import AbstractInput
from mycodo.inputs.sensorutils import calculate_dewpoint
from mycodo.inputs.sensorutils import calculate_vapor_pressure_deficit
from mycodo.inputs.sensorutils import convert_from_x_to_y_unit

# Measurements
measurements_dict = {
0: {
'measurement': 'temperature',
'unit': 'C'
},
1: {
'measurement': 'humidity',
'unit': 'percent'
},
2: {
'measurement': 'dewpoint',
'unit': 'C'
},
3: {
'measurement': 'vapor_pressure_deficit',
'unit': 'Pa'
}
}

# Input information
INPUT_INFORMATION = {
'input_name_unique': 'TH16_10_Generic',
'input_manufacturer': 'Sonoff',
'input_name': 'TH16/10 (Tasmota firmware) with AM2301/Si7021',
'input_library': 'requests',
'measurements_name': 'Humidity/Temperature',
'measurements_dict': measurements_dict,
'url_manufacturer': 'https://sonoff.tech/product/wifi-diy-smart-switches/th10-th16',
'measurements_use_same_timestamp': False,

'message': "This Input module allows the use of any temperature/huidity sensor with the TH10/TH16. Changing the Sensor Name option changes the key that's queried from the returned dictionary of measurements. If you would like to use this module with a version of this device that uses the AM2301, change Sensor Name to AM2301.",

'options_enabled': [
'measurements_select',
'period',
'pre_output'
],
'options_disabled': ['interface'],

'dependencies_module': [
('pip-pypi', 'requests', 'requests==2.25.1')
],

'custom_options': [
{
'id': 'ip_address',
'type': 'text',
'default_value': '192.168.0.100',
'required': True,
'name': lazy_gettext('IP Address'),
'phrase': 'The IP address of the device'
},
{
'id': 'sensor_name',
'type': 'text',
'default_value': 'SI7021',
'required': True,
'name': lazy_gettext('Sensor Name'),
'phrase': 'The name of the sensor connected to the device (specific key name in the returned dictionary)'
}
]
}


class InputModule(AbstractInput):
def __init__(self, input_dev, testing=False):
super(InputModule, self).__init__(input_dev, testing=testing, name=__name__)

self.ip_address = None
self.sensor_name = None

if not testing:
self.setup_custom_options(
INPUT_INFORMATION['custom_options'], input_dev)
self.ip_address = self.ip_address.replace(" ", "") # Remove spaces

def get_measurement(self):
self.return_dict = copy.deepcopy(measurements_dict)

url = "http://{ip}/cm?cmnd=status%2010".format(ip=self.ip_address)
r = requests.get(url)
str_json = r.text
dict_data = json.loads(str_json)

self.logger.debug("Returned Data: {}".format(dict_data))

# Convert string to datetime object
datetime_timestmp = datetime.datetime.strptime(dict_data['StatusSNS']['Time'], '%Y-%m-%dT%H:%M:%S')

if (self.sensor_name and
self.sensor_name in dict_data['StatusSNS']):
if ('TempUnit' in dict_data['StatusSNS'] and
dict_data['StatusSNS']['TempUnit']):
# Convert temperature to SI unit Celsius
temp_c = convert_from_x_to_y_unit(
dict_data['StatusSNS']['TempUnit'],
'C',
dict_data['StatusSNS'][self.sensor_name]['Temperature'])
else:
temp_c = dict_data['StatusSNS'][self.sensor_name]['Temperature']

self.value_set(0, temp_c, timestamp=datetime_timestmp)
self.value_set(1, dict_data['StatusSNS'][self.sensor_name]['Humidity'], timestamp=datetime_timestmp)

if self.is_enabled(2) and self.is_enabled(0) and self.is_enabled(1):
dewpoint = calculate_dewpoint(self.value_get(0), self.value_get(1))
self.value_set(2, dewpoint, timestamp=datetime_timestmp)

if self.is_enabled(3) and self.is_enabled(0) and self.is_enabled(1):
vpd = calculate_vapor_pressure_deficit(self.value_get(0), self.value_get(1))
self.value_set(3, vpd, timestamp=datetime_timestmp)
else:
self.logger.error("Key '{}' not found in measurement dict: {}".format(
self.sensor_name, dict_data))

return self.return_dict

1 comment on commit 4cdf5b5

@kizniche
Copy link
Owner Author

Choose a reason for hiding this comment

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

This commit has been mentioned on DIY Automation Forum. There might be relevant details there:

https://forum.kylegabriel.com/t/input-request-am2301-sensor-has-been-replaced-with-si7021-in-sonoff-th16-10/502/8

Please sign in to comment.