diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dad76073..a4966c09 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,150 +4,153 @@ repos: hooks: - id: blacken-docs name: ☕️ Format documentation using black - language: system + language: python files: '\.(rst|md|markdown|py|tex)$' entry: poetry run blacken-docs require_serial: true + - id: codespell + name: ✅ Checking code for misspellings + language: python + types: [text] + exclude: ^poetry\.lock$ + entry: poetry run codespell -L HASS,hass + - id: format + name: ☕️ Formatting code using ruff + language: python + types: [python] + entry: poetry run ruff format + - id: isort + name: 🔀 Sorting all imports with isort + language: python + types: [python] + entry: poetry run isort + - id: mypy + name: 🆎 Performing static type checking using mypy + language: python + types: [python] + entry: poetry run mypy + exclude: ^vulture_whitelist\.py$ + require_serial: true + - id: poetry + name: 📜 Checking pyproject with Poetry + language: python + entry: poetry check + pass_filenames: false + always_run: true + - id: pylint + name: 🌟 Starring code with pylint + language: python + types: [python] + entry: poetry run pylint + exclude: ^vulture_whitelist\.py$ + - id: pyupgrade + name: 🆙 Checking for upgradable syntax with pyupgrade + language: python + types: [python] + entry: poetry run pyupgrade + args: [--py39-plus, --keep-runtime-typing] + - id: ruff + name: 👔 Enforcing style guide with ruff + language: python + types: [python] + entry: poetry run ruff check --fix + exclude: ^vulture_whitelist\.py$ + - id: vulture + name: 🔍 Finding unused Python code with Vulture + language: python + types: [python] + entry: poetry run vulture ecowitt2mqtt tests vulture_whitelist.py + pass_filenames: false + require_serial: true + - id: yamllint + name: 🎗 Checking YAML files with yamllint + language: python + types: [yaml] + entry: poetry run yamllint + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: - id: check-ast name: 🐍 Checking Python AST - language: system + language: python types: [python] entry: poetry run check-ast - id: check-case-conflict name: 🔠 Checking for case conflicts - language: system + language: python entry: poetry run check-case-conflict - id: check-docstring-first name: ℹ️ Checking docstrings are first - language: system + language: python types: [python] entry: poetry run check-docstring-first - id: check-executables-have-shebangs name: 🧐 Checking that executables have shebangs - language: system + language: python types: [text, executable] entry: poetry run check-executables-have-shebangs stages: [commit, push, manual] - id: check-json name: { Checking JSON files - language: system + language: python types: [json] entry: poetry run check-json - id: check-merge-conflict name: 💥 Checking for merge conflicts - language: system + language: python types: [text] entry: poetry run check-merge-conflict - id: check-symlinks name: 🔗 Checking for broken symlinks - language: system + language: python types: [symlink] entry: poetry run check-symlinks - id: check-toml name: ✅ Checking TOML files - language: system + language: python types: [toml] entry: poetry run check-toml - id: check-yaml name: ✅ Checking YAML files - language: system + language: python types: [yaml] entry: poetry run check-yaml - - id: codespell - name: ✅ Checking code for misspellings - language: system - types: [text] - exclude: ^poetry\.lock$ - entry: poetry run codespell -L HASS,hass - id: debug-statements name: 🪵 Checking for debug statements and imports (Python) - language: system + language: python types: [python] entry: poetry run debug-statement-hook - id: detect-private-key name: 🕵️ Detecting private keys - language: system + language: python types: [text] entry: poetry run detect-private-key - id: end-of-file-fixer name: 🔚 Checking end of files - language: system + language: python types: [text] entry: poetry run end-of-file-fixer stages: [commit, push, manual] - id: fix-byte-order-marker name: 🚏 Checking UTF-8 byte order marker - language: system + language: python types: [text] entry: poetry run fix-byte-order-marker - - id: format - name: ☕️ Formatting code using ruff - language: system - types: [python] - entry: poetry run ruff format - - id: isort - name: 🔀 Sorting all imports with isort - language: system - types: [python] - entry: poetry run isort - - id: mypy - name: 🆎 Performing static type checking using mypy - language: system - types: [python] - entry: poetry run mypy - exclude: ^vulture_whitelist\.py$ - require_serial: true - id: no-commit-to-branch name: 🛑 Checking for commit to protected branch - language: system + language: python entry: poetry run no-commit-to-branch pass_filenames: false always_run: true args: - --branch=dev - --branch=main - - id: poetry - name: 📜 Checking pyproject with Poetry - language: system - entry: poetry check - pass_filenames: false - always_run: true - - id: pylint - name: 🌟 Starring code with pylint - language: system - types: [python] - entry: poetry run pylint - exclude: ^vulture_whitelist\.py$ - - id: pyupgrade - name: 🆙 Checking for upgradable syntax with pyupgrade - language: system - types: [python] - entry: poetry run pyupgrade - args: [--py39-plus, --keep-runtime-typing] - - id: ruff - name: 👔 Enforcing style guide with ruff - language: system - types: [python] - entry: poetry run ruff check --fix - exclude: ^vulture_whitelist\.py$ - id: trailing-whitespace name: ✄ Trimming trailing whitespace - language: system + language: python types: [text] entry: poetry run trailing-whitespace-fixer stages: [commit, push, manual] - - id: vulture - name: 🔍 Finding unused Python code with Vulture - language: system - types: [python] - entry: poetry run vulture ecowitt2mqtt tests vulture_whitelist.py - pass_filenames: false - require_serial: true - - id: yamllint - name: 🎗 Checking YAML files with yamllint - language: system - types: [yaml] - entry: poetry run yamllint - repo: https://github.com/AleksaC/hadolint-py rev: v2.12.0.3 diff --git a/tests/data/test_data_processing.py b/tests/data/test_data_processing.py index c0e2ed27..efe2c6e5 100644 --- a/tests/data/test_data_processing.py +++ b/tests/data/test_data_processing.py @@ -35,6 +35,7 @@ from ecowitt2mqtt.helpers.calculator import CalculatedDataPoint, DataPointType from ecowitt2mqtt.helpers.calculator.battery import BooleanBatteryState from ecowitt2mqtt.helpers.calculator.leak import LeakState +from ecowitt2mqtt.helpers.calculator.rainstate import RainState from ecowitt2mqtt.helpers.calculator.temperature import ( FrostRisk, HumidexPerception, @@ -2972,6 +2973,370 @@ def test_precision(device_data: dict[str, Any], ecowitt: Ecowitt) -> None: ), }, ), + ( + "payload_gw2000a_3.json", + { + "ws90_ver": CalculatedDataPoint( + data_point_key="ws90_ver", + value=147, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "runtime": CalculatedDataPoint( + "runtime", + 1574073, + unit=UnitOfTime.SECONDS, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "tempin": CalculatedDataPoint( + "temp", + 71.78, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "humidityin": CalculatedDataPoint( + "humidity", + 59, + unit=PERCENTAGE, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "baromrel": CalculatedDataPoint( + "barom", + 28.476, + unit=UnitOfPressure.INHG, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "baromabs": CalculatedDataPoint( + "barom", + 28.476, + unit=UnitOfPressure.INHG, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "temp": CalculatedDataPoint( + "temp", + 51.44, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "humidity": CalculatedDataPoint( + "humidity", + 76, + unit=PERCENTAGE, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "winddir": CalculatedDataPoint( + "winddir", + 181, + unit=DEGREE, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "windspeed": CalculatedDataPoint( + "wind", + 1.79, + unit=UnitOfSpeed.MILES_PER_HOUR, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "windgust": CalculatedDataPoint( + "gust", + 4.25, + unit=UnitOfSpeed.MILES_PER_HOUR, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "maxdailygust": CalculatedDataPoint( + "gust", + 12.75, + unit=UnitOfSpeed.MILES_PER_HOUR, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "solarradiation": CalculatedDataPoint( + "solarradiation", + 0.00, + unit=UnitOfIlluminance.WATTS_PER_SQUARE_METER, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "solarradiation_perceived": CalculatedDataPoint( + "solarradiation_perceived", + 0.0, + unit=PERCENTAGE, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "uv": CalculatedDataPoint( + "uv", + 0, + unit=UV_INDEX, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "safe_exposure_time_skin_type_1": CalculatedDataPoint( + "safe_exposure_time_skin_type_1", + None, + unit=UnitOfTime.MINUTES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "safe_exposure_time_skin_type_2": CalculatedDataPoint( + "safe_exposure_time_skin_type_2", + None, + unit=UnitOfTime.MINUTES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "safe_exposure_time_skin_type_3": CalculatedDataPoint( + "safe_exposure_time_skin_type_3", + None, + unit=UnitOfTime.MINUTES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "safe_exposure_time_skin_type_4": CalculatedDataPoint( + "safe_exposure_time_skin_type_4", + None, + unit=UnitOfTime.MINUTES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "safe_exposure_time_skin_type_5": CalculatedDataPoint( + "safe_exposure_time_skin_type_5", + None, + unit=UnitOfTime.MINUTES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "safe_exposure_time_skin_type_6": CalculatedDataPoint( + "safe_exposure_time_skin_type_6", + None, + unit=UnitOfTime.MINUTES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "rrain_piezo": CalculatedDataPoint( + "rrain_piezo", + 0.000, + unit=UnitOfPrecipitationRate.INCHES_PER_HOUR, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "erain_piezo": CalculatedDataPoint( + "rain_piezo", + 0.000, + unit=UnitOfAccumulatedPrecipitation.INCHES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "hrain_piezo": CalculatedDataPoint( + "rain_piezo", + 0.000, + unit=UnitOfAccumulatedPrecipitation.INCHES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "drain_piezo": CalculatedDataPoint( + "rain_piezo", + 0.000, + unit=UnitOfAccumulatedPrecipitation.INCHES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "wrain_piezo": CalculatedDataPoint( + "rain_piezo", + 0.181, + unit=UnitOfAccumulatedPrecipitation.INCHES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "mrain_piezo": CalculatedDataPoint( + "rain_piezo", + 0.094, + unit=UnitOfAccumulatedPrecipitation.INCHES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "yrain_piezo": CalculatedDataPoint( + "rain_piezo", + 23.264, + unit=UnitOfAccumulatedPrecipitation.INCHES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "srain_piezo": CalculatedDataPoint( + "rain_piezo", + 0, + unit=None, + attributes={}, + data_type=DataPointType.BOOLEAN, + ), + "ws90cap_volt": CalculatedDataPoint( + "volt", + 5.0, + unit=UnitOfElectricPotential.VOLT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "wh90batt": CalculatedDataPoint( + "batt", + 3.04, + unit=UnitOfElectricPotential.VOLT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "dewpoint": CalculatedDataPoint( + "dewpoint", + 52.958965353493454, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "feelslike": CalculatedDataPoint( + "feelslike", + 74.5, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "heatindex": CalculatedDataPoint( + "heatindex", + 73.85900000000001, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "windchill": CalculatedDataPoint( + "windchill", + None, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "humidityabs": CalculatedDataPoint( + data_point_key="humidityabs", + value=0.0006244952780717129, + unit=UnitOfVolume.POUNDS_PER_CUBIC_FOOT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "humidityabsin": CalculatedDataPoint( + data_point_key="humidityabsin", + value=0.0005861001233730504, + unit=UnitOfVolume.POUNDS_PER_CUBIC_FOOT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "thermalperception": CalculatedDataPoint( + data_point_key="thermalperception", + value=ThermalPerception.VERY_COMFORTABLE, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "frostpoint": CalculatedDataPoint( + data_point_key="frostpoint", + value=47.136193624907584, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "frostrisk": CalculatedDataPoint( + data_point_key="frostrisk", + value=FrostRisk.NO_RISK, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "simmerindex": CalculatedDataPoint( + data_point_key="simmerindex", + value=81.156695, + unit=UnitOfTemperature.FAHRENHEIT, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "simmerzone": CalculatedDataPoint( + data_point_key="simmerzone", + value=SimmerZone.COMFORTABLE, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "beaufortscale": CalculatedDataPoint( + data_point_key="beaufortscale", + value=1, + unit=None, + attributes={ + "description": "Light air", + "sea_conditions": ( + "Ripples with appearance of scales are formed, without " + "foam crests" + ), + "land_conditions": ( + "Direction shown by smoke drift but not by wind vanes" + ), + }, + data_type=DataPointType.NON_BOOLEAN, + ), + "humidex": CalculatedDataPoint( + data_point_key="humidex", + value=26, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "humidex_perception": CalculatedDataPoint( + data_point_key="humidex_perception", + value=HumidexPerception.LITTLE_TO_NO_DISCOMFORT, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "relative_strain_index": CalculatedDataPoint( + data_point_key="relative_strain_index", + value=None, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "relative_strain_index_perception": CalculatedDataPoint( + data_point_key="relative_strain_index_perception", + value=None, + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "heap": CalculatedDataPoint( + data_point_key="heap", + value=1574073.0, + unit=UnitOfMemory.BYTES, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "winddir_name": CalculatedDataPoint( + data_point_key="winddir_name", + value="S", + unit=None, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + "interval": CalculatedDataPoint( + data_point_key="interval", + value=16.0, + unit=UnitOfTime.SECONDS, + attributes={}, + data_type=DataPointType.NON_BOOLEAN, + ), + }, + ), ( "payload_gw2000a_2.json", { diff --git a/tests/fixtures/payload_gw2000a_3.json b/tests/fixtures/payload_gw2000a_3.json new file mode 100644 index 00000000..7c7fcf4c --- /dev/null +++ b/tests/fixtures/payload_gw2000a_3.json @@ -0,0 +1,33 @@ +{ + "PASSKEY": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "stationtype": "GW2000A_V3.1.5", + "runtime": "1574073", + "heap": "156456", + "dateutc": "2024-10-03 19:42:19", + "tempinf": "71.78", + "humidityin": "59", + "baromrelin": "30.035", + "baromabsin": "29.394", + "tempf": "51.44", + "humidity": "76", + "winddir": "181", + "windspeedmph": "1.79", + "windgustmph": "4.25", + "maxdailygust": "12.75", + "solarradiation": "0.00", + "uv": "0", + "rrain_piezo": "0.000", + "erain_piezo": "0.000", + "hrain_piezo": "0.000", + "drain_piezo": "0.000", + "wrain_piezo": "0.181", + "mrain_piezo": "0.094", + "yrain_piezo": "23.264", + "ws90cap_volt": "5.0", + "ws90_ver": "147", + "srain_piezo": "0", + "wh90batt": "3.04", + "freq": "868M", + "model": "GW2000A", + "interval": "16" +}