├── .github └── workflows │ ├── close_inactive_issuses.yml │ └── close_stale_ pull_requests.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── NANO-CUL.md ├── NANOCUL-DOCKER.md ├── README.md ├── RTL232.md ├── __init__.py ├── app.py ├── config.py.dist ├── data ├── .gitkeep ├── 43430778-day-report.csv ├── 43430778-report.csv ├── 43430778.json └── default_data.json ├── docs ├── .gitkeep ├── DS_IZAR_RADIO_COMPACT_INDUCTIVE_de_20170906_V2_0.pdf ├── DVB-T-DAB-FM- RTL2832U-FC0012 Chip.png ├── MA_IZAR_RADIO_COMPACT_INDUCTIVE_ml_20170529_V2_0.pdf ├── MA_Installation_guide_IZAR_RCi_02_2016_ml_20180314.pdf ├── RB3B_DVBT.png ├── SDR_STICK.png ├── build-rtl-wmbus.md ├── build-wmbusmeters.md ├── d1Mini868Mhz.png ├── d1min_cc1101.png ├── diehl_metering.jpg ├── esphome-watermeter.png ├── ha-card.png ├── ha-card2.png ├── homeassistant │ ├── README.md │ ├── card02.png │ ├── card1.png │ ├── config │ │ ├── input_numbers │ │ │ └── water.yaml │ │ └── sensor │ │ │ ├── smartmeter-water.yaml │ │ │ └── smartmeter-watercosts.yaml │ ├── details.png │ ├── lovelace │ │ ├── cards │ │ │ └── smartmeter-water │ │ │ │ ├── card-water-days.yaml │ │ │ │ ├── card-water-overview.yaml │ │ │ │ └── card-water-usage.yaml │ │ └── views │ │ │ └── smartmeter-water.yaml │ ├── mqtt-data.json │ ├── view_watermeter.png │ ├── water_barcard.png │ └── water_homekitpanel_card.png ├── liter-pro-stunde.png ├── logging.png ├── nanoCUL868.png ├── nanocul_v3 │ ├── CUL_V3_MBUS.hex │ ├── README.md │ └── nanocul.jpg ├── rpw.png ├── rtl-sdr4linux_quickstartguidev20.pdf ├── sampedata.json ├── top-nanocul.png ├── top-rtlsdr.png ├── wmbusdata.json ├── wmbusmeters-nano_cul.md └── wmbusmeters-with-rtl-sdr.md ├── esphome ├── .gitignore ├── README.md ├── archive │ └── wm-d1mini_izar-wmbus.yaml ├── atom_lite_watermeter.yaml ├── custom_components │ ├── backup │ │ ├── README.md │ │ ├── __init__.py │ │ ├── backup.cpp │ │ └── backup.h │ ├── crash_info │ │ ├── README.md │ │ ├── __init__.py │ │ ├── crash_info.cpp │ │ └── crash_info.h │ ├── heapmon │ │ ├── README.md │ │ ├── __init__.py │ │ ├── heapmon.cpp │ │ ├── heapmon.h │ │ └── sensor.py │ ├── influxdb │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── __init__.py │ │ ├── influxdb_writer.cpp │ │ └── influxdb_writer.h │ ├── izar-wmbus │ │ ├── README.md │ │ ├── izar_utils.cpp │ │ ├── izar_utils.h │ │ ├── izar_wmbus.cpp │ │ ├── izar_wmbus.h │ │ ├── library.json │ │ └── wmbus_t_cc1101_config.h │ ├── izar_meter.h │ ├── ping │ │ ├── __init__.py │ │ ├── ping.h │ │ ├── ping_esp32.h │ │ ├── ping_esp8266.h │ │ ├── ping_sock.c │ │ ├── ping_sock.h │ │ └── sensor.py │ ├── startup │ │ ├── README.md │ │ ├── __init__.py │ │ ├── sensor.py │ │ ├── startup.cpp │ │ └── startup.h │ ├── syslog │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── __init__.py │ │ ├── syslog_component.cpp │ │ └── syslog_component.h │ ├── water_statistics │ │ ├── README.md │ │ ├── __init__.py │ │ ├── sensor.py │ │ ├── water_statistics.cpp │ │ └── water_statistics.h │ ├── wmbus │ │ ├── __init__.py │ │ ├── driver.h │ │ ├── driver_amiplus.h │ │ ├── driver_apator_08.h │ │ ├── driver_apator_16_2.h │ │ ├── driver_apatoreitn.h │ │ ├── driver_bmeters.h │ │ ├── driver_c5isf.h │ │ ├── driver_compact5.h │ │ ├── driver_elf.h │ │ ├── driver_evo868.h │ │ ├── driver_fhkvdataiii.h │ │ ├── driver_hydrocalm3.h │ │ ├── driver_hydrus.h │ │ ├── driver_iperl.h │ │ ├── driver_itron.h │ │ ├── driver_izar.h │ │ ├── driver_mkradio3.h │ │ ├── driver_mkradio4.h │ │ ├── driver_qheat.h │ │ ├── driver_qwater.h │ │ ├── driver_sharky774.h │ │ ├── driver_topaseskr.h │ │ ├── driver_ultrimis.h │ │ ├── driver_unismart.h │ │ ├── driver_vario451.h │ │ ├── drivers.h │ │ ├── sensor │ │ │ └── __init__.py │ │ ├── version.h │ │ ├── wmbus.cpp │ │ └── wmbus.h │ └── wmbusgw │ │ ├── __init__.py │ │ ├── wmbusgw_component.cpp │ │ └── wmbusgw_component.h ├── docs │ ├── CC1101 SPI Adaptor_bottom.png │ ├── CC1101 SPI Adaptor_top.png │ ├── CC1101-868mhz-radio-module-pinout.jpg │ ├── CC1101.png │ ├── CC1101_Board.png │ ├── D1MINI-ESP32.png │ ├── E07-900M10S-CC1101.png │ ├── E07-900M10S-CC1101_pins.png │ ├── E07-900MBL-01.jpg │ ├── Ebyte E07-900MM10S.txt │ ├── IMAGE 2023-04-23 13:17:26.jpg │ ├── analog_vs_wmbus.jpg │ ├── az-delivery-devkit-v4.png │ ├── cc1101_board_pins.png │ ├── cc1101_board_pins.pxm │ ├── cc1101_platine.png │ ├── d1Mini-wemos.png │ ├── d1Mini868Mhz.png │ ├── d1Mini_pinlayout.png │ ├── d1mini-esp32-cc1101.png │ ├── d1mini-esp8266MOD-12F.png │ ├── d1mini32_8266.png │ ├── d1mini_CC1101.jpg │ ├── d1miniesp32.png │ ├── eshome_webui.png │ ├── esp32-devkit_v1.png │ ├── esp32-devkitv1.png │ ├── esp32_cc1101.png │ ├── esp32_devkit_v1.jpg │ ├── esp32_devkit_v1_cc1011.png │ ├── esphome-components-1.4.8.zip │ ├── esphome.png │ ├── esphome_nodemcu.png │ ├── ha-Device.png │ ├── ha_rssi.png │ ├── ha_water-meter-esp.png │ ├── ha_water.png │ ├── ha_water_day.png │ ├── ha_water_year.png │ ├── ha_waterdisplay.png │ ├── ha_wlan.png │ ├── homeassistant_service_call.png │ ├── homeassistat-water-meter-izar.png │ ├── mdmini_v150.zip │ ├── memory_usage.png │ ├── nodemcu_cc1101.jpg │ ├── nodemcu_v3.png │ ├── postman_get_config.png │ ├── schaltplan.png │ ├── water-meter-d1mini.png │ ├── water-meter-esp.png │ ├── water-meter-izar.png │ ├── water-meter2-esp.png │ ├── watermeter-webserver3.png │ ├── webserver_3_0.png │ ├── wlan_lgi.png │ └── wmbus_ szczepan.md ├── template_secrets.yaml ├── testcases │ ├── README.md │ ├── WLAN_ACCESS.png │ ├── water-meter-dm32-test.bin │ ├── water-meter-esp32-izar-test-dev.bin │ ├── water-meter-esp32-izar-test.bin │ ├── water-meter-esp32-izar-test2.bin │ ├── water-meter-esp32-izar-test2.png │ ├── water-meter-izar-test.bin │ ├── wm-d1mini-izar-test.yaml │ ├── wm-d1mini32-izar-test.yaml │ ├── wm-esp32-izar-test.yaml │ └── wm-esp32-izar-test2.yaml ├── version_3.md ├── water-meter-izar.md ├── water-meter-testcase.yaml ├── watermeter_d1mini.md ├── webserver │ ├── README.md │ ├── v1 │ │ ├── webserver-v1.css │ │ ├── webserver-v1.js │ │ ├── webserver-v1.min.css │ │ └── webserver-v1.min.js │ ├── v2 │ │ ├── home.svg │ │ ├── index.html │ │ ├── index.html.br │ │ ├── index.html.gz │ │ ├── logo.svg │ │ ├── server_index.h │ │ ├── www.js │ │ ├── www.js.br │ │ └── www.js.gz │ ├── v3 │ │ ├── fonts │ │ │ └── Roboto │ │ │ │ ├── LICENSE.txt │ │ │ │ ├── Roboto-Black.ttf │ │ │ │ ├── Roboto-BlackItalic.ttf │ │ │ │ ├── Roboto-Bold.ttf │ │ │ │ ├── Roboto-BoldItalic.ttf │ │ │ │ ├── Roboto-Italic.ttf │ │ │ │ ├── Roboto-Light.ttf │ │ │ │ ├── Roboto-LightItalic.ttf │ │ │ │ ├── Roboto-Medium.ttf │ │ │ │ ├── Roboto-MediumItalic.ttf │ │ │ │ ├── Roboto-Regular.ttf │ │ │ │ ├── Roboto-Thin.ttf │ │ │ │ └── Roboto-ThinItalic.ttf │ │ ├── webserver.css │ │ ├── www.js │ │ ├── www.js.br │ │ └── www.js.gz │ └── v4 │ │ └── www.js ├── wm-check-wmbus.yaml ├── wm-d1mini-simple.yaml ├── wm-d1mini-test.yaml ├── wm-d1mini.yaml ├── wm-d1mini32-simple.yaml ├── wm-d1mini32-test.yaml ├── wm-d1mini32.yaml ├── wm-esp32-simple.yaml ├── wm-esp32-test.yaml ├── wm-esp32.yaml ├── wm-nodemcu-test.yaml └── wm-nodemcu.yaml ├── ha-watermeter.md ├── lib ├── __init__.py ├── calculator.py └── logger.py ├── logs ├── .gitkeep └── data.csv ├── requirements.txt ├── service.template ├── test.py ├── tests ├── .gitkeep ├── 43430778.json ├── test.py └── wmbus.json └── tools └── simpleserver.py /.github/workflows/close_inactive_issuses.yml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' # Run every day at 01:30 5 | 6 | jobs: 7 | close-issues: 8 | 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | 14 | steps: 15 | - uses: actions/stale@v5 16 | with: 17 | days-before-issue-stale: 30 18 | days-before-issue-close: 14 19 | stale-issue-label: "stale" 20 | stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." 21 | close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." 22 | # Wenn diese Aktion niemals Issues schließen soll, lege diesen Wert auf -1 fest. 23 | days-before-pr-stale: 0 24 | days-before-pr-close: 0 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/close_stale_ pull_requests.yml: -------------------------------------------------------------------------------- 1 | name: Close Stale Pull Requests 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' # Run every day at midnight 6 | 7 | jobs: 8 | close_stale_prs: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Close stale pull requests 12 | uses: actions/stale@v5 13 | with: 14 | stale-issue-message: 'This pull request has been automatically closed because it has been inactive for more than 14 days. Please reopen if you still intend to submit this pull request.' 15 | days-before-stale: 14 16 | days-before-close: 0 17 | stale-pr-message: 'This pull request has been marked as stale because it has been inactive for more than 14 days. Please update this pull request or it will be automatically closed in 7 days.' 18 | stale-pr-label: stale 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project files 2 | settings.py 3 | .DS_Store 4 | .env 5 | .history 6 | config.py 7 | internal/ 8 | data/43430778.json 9 | 10 | # Byte-compiled / optimized / DLL files 11 | __pycache__/ 12 | *.py[cod] 13 | *$py.class 14 | 15 | # C extensions 16 | *.so 17 | 18 | # Distribution / packaging 19 | .Python 20 | build/ 21 | develop-eggs/ 22 | dist/ 23 | downloads/ 24 | eggs/ 25 | .eggs/ 26 | lib64/ 27 | parts/ 28 | sdist/ 29 | var/ 30 | wheels/ 31 | pip-wheel-metadata/ 32 | share/python-wheels/ 33 | *.egg-info/ 34 | .installed.cfg 35 | *.egg 36 | MANIFEST 37 | 38 | # PyInstaller 39 | # Usually these files are written by a python script from a template 40 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 41 | *.manifest 42 | *.spec 43 | 44 | # Installer logs 45 | pip-log.txt 46 | pip-delete-this-directory.txt 47 | 48 | # Unit test / coverage reports 49 | htmlcov/ 50 | .tox/ 51 | .nox/ 52 | .coverage 53 | .coverage.* 54 | .cache 55 | nosetests.xml 56 | coverage.xml 57 | *.cover 58 | *.py,cover 59 | .hypothesis/ 60 | .pytest_cache/ 61 | 62 | # Translations 63 | *.mo 64 | *.pot 65 | 66 | # Django stuff: 67 | *.log 68 | local_settings.py 69 | db.sqlite3 70 | db.sqlite3-journal 71 | 72 | # Flask stuff: 73 | instance/ 74 | .webassets-cache 75 | 76 | # Scrapy stuff: 77 | .scrapy 78 | 79 | # Sphinx documentation 80 | docs/_build/ 81 | 82 | # PyBuilder 83 | target/ 84 | 85 | # Jupyter Notebook 86 | .ipynb_checkpoints 87 | 88 | # IPython 89 | profile_default/ 90 | ipython_config.py 91 | 92 | # pyenv 93 | .python-version 94 | 95 | # pipenv 96 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 97 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 98 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 99 | # install all needed dependencies. 100 | #Pipfile.lock 101 | 102 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 103 | __pypackages__/ 104 | 105 | # Celery stuff 106 | celerybeat-schedule 107 | celerybeat.pid 108 | 109 | # SageMath parsed files 110 | *.sage.py 111 | 112 | # Environments 113 | .env 114 | .venv 115 | env/ 116 | venv/ 117 | ENV/ 118 | env.bak/ 119 | venv.bak/ 120 | 121 | # Spyder project settings 122 | .spyderproject 123 | .spyproject 124 | 125 | # Rope project settings 126 | .ropeproject 127 | 128 | # mkdocs documentation 129 | /site 130 | 131 | # mypy 132 | .mypy_cache/ 133 | .dmypy.json 134 | dmypy.json 135 | 136 | # Pyre type checker 137 | .pyre/ 138 | data/43430778.json 139 | esphome/develop_esphome.code-workspace 140 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "/usr/local/bin/python3", 3 | "files.associations": { 4 | "*.tcc": "cpp", 5 | "cctype": "cpp", 6 | "clocale": "cpp", 7 | "cmath": "cpp", 8 | "complex": "cpp", 9 | "cstdarg": "cpp", 10 | "cstddef": "cpp", 11 | "cstdio": "cpp", 12 | "cstdlib": "cpp", 13 | "cstring": "cpp", 14 | "ctime": "cpp", 15 | "cwchar": "cpp", 16 | "cwctype": "cpp", 17 | "bitset": "cpp", 18 | "deque": "cpp", 19 | "list": "cpp", 20 | "vector": "cpp", 21 | "exception": "cpp", 22 | "fstream": "cpp", 23 | "iomanip": "cpp", 24 | "iosfwd": "cpp", 25 | "iostream": "cpp", 26 | "istream": "cpp", 27 | "limits": "cpp", 28 | "memory": "cpp", 29 | "new": "cpp", 30 | "ostream": "cpp", 31 | "sstream": "cpp", 32 | "stdexcept": "cpp", 33 | "streambuf": "cpp", 34 | "array": "cpp", 35 | "cfenv": "cpp", 36 | "cinttypes": "cpp", 37 | "cstdint": "cpp", 38 | "functional": "cpp", 39 | "hashtable": "cpp", 40 | "random": "cpp", 41 | "tuple": "cpp", 42 | "type_traits": "cpp", 43 | "unordered_map": "cpp", 44 | "utility": "cpp", 45 | "typeinfo": "cpp", 46 | "atomic": "cpp", 47 | "bit": "cpp", 48 | "chrono": "cpp", 49 | "codecvt": "cpp", 50 | "compare": "cpp", 51 | "concepts": "cpp", 52 | "condition_variable": "cpp", 53 | "map": "cpp", 54 | "set": "cpp", 55 | "string": "cpp", 56 | "algorithm": "cpp", 57 | "iterator": "cpp", 58 | "memory_resource": "cpp", 59 | "numeric": "cpp", 60 | "optional": "cpp", 61 | "ratio": "cpp", 62 | "string_view": "cpp", 63 | "system_error": "cpp", 64 | "initializer_list": "cpp", 65 | "mutex": "cpp", 66 | "numbers": "cpp", 67 | "semaphore": "cpp", 68 | "stop_token": "cpp", 69 | "thread": "cpp", 70 | "typeindex": "cpp", 71 | "variant": "cpp" 72 | } 73 | } -------------------------------------------------------------------------------- /NANO-CUL.md: -------------------------------------------------------------------------------- 1 | # wmbusmeters with NANO-CUL 2 | 3 | ## Raspbian Buster + wmbusmeters with NANO-CUL (mbus) 868 Mhz 4 | 5 | **NANO-CUL (mbus) 868** is a lot easier to use because it only requires `wmbusmeters`. The resources (memory) required are also less compared to the variant with RTL-SDR and rtl-wmbus. 6 | 7 | 8 | ![nanoCUL868](docs/nanoCUL868.png) 9 | Please not, that you do need the NANO-CUL (mbus) 868 Mhz for `wmbusmeters` **not for** `***\*FHEM\****`!! . smart-home-komponente.net can flash the firmware for `wmbusmeters`. 10 |
11 | 12 | ### Install dependencies 13 | 14 | - `wmbusmeters` 15 | Program receives and decodes WMBus telegrams 16 | https://github.com/weetmuts/wmbusmeters, 17 | build see: [build-wmbusmeters](docs/build-wmbusmeters.md) 18 | 19 | ### Install dependencies 20 | 21 | - `wmbusmeters` 22 | Program receives and decodes WMBus telegrams 23 | https://github.com/weetmuts/wmbusmeters, 24 | build see: [build-wmbusmeters](docs/build-wmbusmeters.md) 25 | 26 | ## Integration 27 | 28 | In the `wmbusmeters` reporting mode, data will be published to the MQTT broker topic "`tele/wasser/verbrauch`". 29 | 30 | This data can be subscribed to and processed by other applications. From this point forward your options are endless. Example for simple mode - publish all smartmeter display data: 31 | 32 | ```json 33 | { 34 | "media": "water", 35 | "meter": "izar", 36 | "name": "watermeter", 37 | "id": "1231150", 38 | "total_m3": 166.625, 39 | "last_month_total_m3": 162.614, 40 | "last_month_measure_date": "2020-07-01", 41 | "remaining_battery_life_y": 13, 42 | "current_alarms": "no_alarm", 43 | "previous_alarms": "no_alarm", 44 | "timestamp": "2020-07-16T11:32:38Z" 45 | } 46 | ``` 47 | 48 | ### Continuous Daemon/Service 49 | 50 | You most probably want to execute the program **continuously in the background**. This can be done either by using the internal daemon or cron. 51 | 52 | **Attention:** Daemon mode must be enabled in the configuration file (default). 53 | 54 | 1. Systemd service - on systemd powered systems the **recommended** option 55 | 56 | ```bash 57 | sudo cp /opt/ha-watermeter/service.template /etc/systemd/system/ha-watermeter.service 58 | 59 | sudo systemctl daemon-reload 60 | sudo systemctl start ha-watermeter.service 61 | sudo systemctl status ha-watermeter.service 62 | 63 | sudo systemctl enable ha-watermeter.service 64 | ``` 65 | -------------------------------------------------------------------------------- /NANOCUL-DOCKER.md: -------------------------------------------------------------------------------- 1 | # Docker + wmbusmeters with NANO-CUL (mbus) 868 Mhz 2 | wmbusmeters docker is able to detect attachment and removal of wmbus dongles and to provide that functionality within docker image it must be started in privileged mode to have access to hosts /dev/ content. 3 | 4 | see: https://hub.docker.com/r/weetmuts/wmbusmeters 5 |
6 | 7 | ![nanoCUL868](docs/nanocul_v3/nanocul.jpg) 8 | 9 | More Info see: [Testcase Flash CUL-Stick](docs/nanocul_v3/README.md) 10 | 11 | https://www.smart-home-komponente.de/nano-cul/nano-cul-868-extra/ 12 | 13 | 14 | ## Docker wmbusmeters 15 | 16 | With this bash script, wmbusmeters is installed as a docker application 17 | 18 | 19 | ```bash 20 | #!/bin/bash 21 | # ---------------------------------- 22 | # sudo sh wmbusmeters.sh 23 | # ---------------------------------- 24 | DOCKER_APPSDIR=/apps/ 25 | DOCKER_TIMEZONE=Europe/Berlin 26 | DOCKERIMAGE=weetmuts/wmbusmeters 27 | CONTAINERLABEL=wmbusmeters 28 | APPSDATA=$PWD${DOCKER_APPSDIR}${CONTAINERLABEL} 29 | 30 | echo "Create persistent data folder and log folder" 31 | mkdir -p ${APPSDATA} 2>&1 32 | 33 | echo "Try to remove previuos installation..." 34 | docker stop ${CONTAINERLABEL} >/dev/null 2>&1 35 | docker rm ${CONTAINERLABEL} >/dev/null 2>&1 36 | 37 | echo "Install Docker container ${CONTAINERLABEL}." 38 | docker run --detach --interactive \ 39 | --privileged \ 40 | --name=${CONTAINERLABEL} \ 41 | --restart=always \ 42 | --volume /etc/localtime:/etc/localtime:ro \ 43 | --volume ${APPSDATA}:/wmbusmeters_data \ 44 | --volume /dev/:/dev/ \ 45 | ${DOCKERIMAGE} 46 | 47 | echo "Docker container ${CONTAINERLABEL} ready." 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /RTL232.md: -------------------------------------------------------------------------------- 1 | # Raspbian Buster + DVB-T receiver 2 | 3 | 4 | ### ![RB3B_DVBT](docs/RB3B_DVBT.png) 5 |
6 | 7 | **Andoer Tragbarer Mini Digitaler TV Stock USB 2.0 DVB-T+DAB+FM+RTL2832U+FC0012 Chip Unterstützung SDR** 8 | 9 | ![SDR_STICK](docs/SDR_STICK.png) 10 | 11 | 12 | Digitaler TV Stock USB 2.0 DVB-T + DAB + FM + RTL2832U + FC0012 see: [Amazon](https://amzn.eu/d/8NNDo6A). 13 | 14 | Details and Installation see: [wmbusmeters-with-rtl-sdr.md](docs/wmbusmeters-with-rtl-sdr.md) 15 | 16 | 17 | ### Requirements 18 | 19 | - Water meter with IZAR module (Diehl IZAR RC 868 I R4 PL), 20 | IZAR Radio Compact Hall is designed for mobile reading and fixed network remote reading of Diehl Metering meters. 21 |
22 | - Supported DVB-T receiver or Nano CUL Adapter, 23 | Andoer Tragbarer Mini Digitaler TV Stock USB 2.0 DVB-T + DAB + FM + RTL2832U + FC0012 Chip Unterstützung SDR Stimmer Empfänger 24 |
25 | - A computer. I’m using Raspbian Buster on a Raspberry Pi 3B+, but any Linux, macOS should work 26 | 27 | 28 | ## Integration 29 | 30 | In the `wmbusmeters` reporting mode, data will be published to the MQTT broker topic "`tele/wasser/verbrauch`". 31 | 32 | This data can be subscribed to and processed by other applications. From this point forward your options are endless. Example for simple mode - publish all smartmeter display data: 33 | 34 | ```json 35 | { 36 | "media": "water", 37 | "meter": "izar", 38 | "name": "watermeter", 39 | "id": "1231150", 40 | "total_m3": 166.625, 41 | "last_month_total_m3": 162.614, 42 | "last_month_measure_date": "2020-07-01", 43 | "remaining_battery_life_y": 13, 44 | "current_alarms": "no_alarm", 45 | "previous_alarms": "no_alarm", 46 | "timestamp": "2020-07-16T11:32:38Z" 47 | } 48 | ``` 49 | 50 | ### Continuous Daemon/Service 51 | 52 | You most probably want to execute the program **continuously in the background**. This can be done either by using the internal daemon or cron. 53 | 54 | **Attention:** Daemon mode must be enabled in the configuration file (default). 55 | 56 | 1. Systemd service - on systemd powered systems the **recommended** option 57 | 58 | ```bash 59 | sudo cp /opt/ha-watermeter/service.template /etc/systemd/system/ha-watermeter.service 60 | 61 | sudo systemctl daemon-reload 62 | sudo systemctl start ha-watermeter.service 63 | sudo systemctl status ha-watermeter.service 64 | 65 | sudo systemctl enable ha-watermeter.service 66 | ``` 67 | 68 | 69 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | import config 2 | name = 'watermeter' -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/data/.gitkeep -------------------------------------------------------------------------------- /data/43430778-day-report.csv: -------------------------------------------------------------------------------- 1 | watermeter,43430778,2020-07,2020-07-17T13:50:00Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 2 | watermeter,43430778,2020-07,2020-07-17T13:50:26Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 3 | watermeter,43430778,2020-07,2020-07-17T13:50:44Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 4 | watermeter,43430778,2020-07,2020-07-17T13:51:26Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 5 | watermeter,43430778,2020-07,2020-07-17T13:51:35Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 6 | watermeter,43430778,2020-07,2020-07-17T13:51:43Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 7 | watermeter,43430778,2020-07,2020-07-17T13:52:52Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 8 | watermeter,43430778,2020-07,2020-07-17T13:53:01Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 9 | watermeter,43430778,2020-07,2020-07-17T13:53:17Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 10 | watermeter,43430778,2020-07,2020-07-17T13:53:52Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 11 | watermeter,43430778,2020-07,2020-07-17T13:54:10Z,166.887,0.078,4.273,49.157,166.809,162.614,117.73,no_alarm,no_alarm 12 | watermeter,43430778,2020-07,2020-07-17T13:54:43Z,166.888,0.079,4.274,49.158,166.809,162.614,117.73,no_alarm,no_alarm 13 | watermeter,43430778,2020-07,2020-07-17T13:55:43Z,166.893,0.084,4.279,49.163,166.809,162.614,117.73,no_alarm,no_alarm 14 | watermeter,43430778,2020-07,2020-07-17T13:57:09Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 15 | watermeter,43430778,2020-07,2020-07-17T13:57:26Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 16 | watermeter,43430778,2020-07,2020-07-17T13:59:00Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 17 | watermeter,43430778,2020-07,2020-07-17T13:59:09Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 18 | watermeter,43430778,2020-07,2020-07-17T13:59:26Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 19 | watermeter,43430778,2020-07,2020-07-17T13:59:43Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 20 | watermeter,43430778,2020-07,2020-07-17T13:59:52Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 21 | watermeter,43430778,2020-07,2020-07-17T14:00:00Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 22 | watermeter,43430778,2020-07,2020-07-17T14:00:17Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 23 | watermeter,43430778,2020-07,2020-07-17T14:00:34Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 24 | watermeter,43430778,2020-07,2020-07-17T14:00:43Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 25 | watermeter,43430778,2020-07,2020-07-17T14:00:52Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 26 | watermeter,43430778,2020-07,2020-07-17T14:01:01Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 27 | watermeter,43430778,2020-07,2020-07-17T14:01:09Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 28 | watermeter,43430778,2020-07,2020-07-17T14:01:35Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 29 | watermeter,43430778,2020-07,2020-07-17T14:01:43Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,no_alarm 30 | watermeter,43430778,2020-07,2020-07-17T14:01:52Z,166.899,0.09,4.285,49.169,166.809,162.614,117.73,no_alarm,No alarm 31 | watermeter,43430778,2022-02,2022-02-11T08:22:10Z,343.913,0.016,2.734,226.183,343.897,341.179,117.73,no_alarm,No alarm 32 | watermeter,43430778,2022-02,2022-02-21T23:57:38Z,347.226,0.157,6.047,229.496,347.069,341.179,117.73,no_alarm,no_alarm 33 | -------------------------------------------------------------------------------- /data/43430778-report.csv: -------------------------------------------------------------------------------- 1 | watermeter,43430778,2020-07-17,13:50:00,2020-07-17T13:50:00Z,166.887,162.614,117.73,no_alarm,no_alarm 2 | watermeter,43430778,2020-07-17,13:50:26,2020-07-17T13:50:26Z,166.887,162.614,117.73,no_alarm,no_alarm 3 | watermeter,43430778,2020-07-17,13:50:44,2020-07-17T13:50:44Z,166.887,162.614,117.73,no_alarm,no_alarm 4 | watermeter,43430778,2020-07-17,13:51:26,2020-07-17T13:51:26Z,166.887,162.614,117.73,no_alarm,no_alarm 5 | watermeter,43430778,2020-07-17,13:51:35,2020-07-17T13:51:35Z,166.887,162.614,117.73,no_alarm,no_alarm 6 | watermeter,43430778,2020-07-17,13:51:43,2020-07-17T13:51:43Z,166.887,162.614,117.73,no_alarm,no_alarm 7 | watermeter,43430778,2020-07-17,13:52:52,2020-07-17T13:52:52Z,166.887,162.614,117.73,no_alarm,no_alarm 8 | watermeter,43430778,2020-07-17,13:53:01,2020-07-17T13:53:01Z,166.887,162.614,117.73,no_alarm,no_alarm 9 | watermeter,43430778,2020-07-17,13:53:17,2020-07-17T13:53:17Z,166.887,162.614,117.73,no_alarm,no_alarm 10 | watermeter,43430778,2020-07-17,13:53:52,2020-07-17T13:53:52Z,166.887,162.614,117.73,no_alarm,no_alarm 11 | watermeter,43430778,2020-07-17,13:54:10,2020-07-17T13:54:10Z,166.887,162.614,117.73,no_alarm,no_alarm 12 | watermeter,43430778,2020-07-17,13:54:43,2020-07-17T13:54:43Z,166.888,162.614,117.73,no_alarm,no_alarm 13 | watermeter,43430778,2020-07-17,13:55:43,2020-07-17T13:55:43Z,166.893,162.614,117.73,no_alarm,no_alarm 14 | watermeter,43430778,2020-07-17,13:57:09,2020-07-17T13:57:09Z,166.899,162.614,117.73,no_alarm,no_alarm 15 | watermeter,43430778,2020-07-17,13:57:26,2020-07-17T13:57:26Z,166.899,162.614,117.73,no_alarm,no_alarm 16 | watermeter,43430778,2020-07-17,13:59:00,2020-07-17T13:59:00Z,166.899,162.614,117.73,no_alarm,no_alarm 17 | watermeter,43430778,2020-07-17,13:59:09,2020-07-17T13:59:09Z,166.899,162.614,117.73,no_alarm,no_alarm 18 | watermeter,43430778,2020-07-17,13:59:26,2020-07-17T13:59:26Z,166.899,162.614,117.73,no_alarm,no_alarm 19 | watermeter,43430778,2020-07-17,13:59:43,2020-07-17T13:59:43Z,166.899,162.614,117.73,no_alarm,no_alarm 20 | watermeter,43430778,2020-07-17,13:59:52,2020-07-17T13:59:52Z,166.899,162.614,117.73,no_alarm,no_alarm 21 | watermeter,43430778,2020-07-17,14:00:00,2020-07-17T14:00:00Z,166.899,162.614,117.73,no_alarm,no_alarm 22 | watermeter,43430778,2020-07-17,14:00:17,2020-07-17T14:00:17Z,166.899,162.614,117.73,no_alarm,no_alarm 23 | watermeter,43430778,2020-07-17,14:00:34,2020-07-17T14:00:34Z,166.899,162.614,117.73,no_alarm,no_alarm 24 | watermeter,43430778,2020-07-17,14:00:43,2020-07-17T14:00:43Z,166.899,162.614,117.73,no_alarm,no_alarm 25 | watermeter,43430778,2020-07-17,14:00:52,2020-07-17T14:00:52Z,166.899,162.614,117.73,no_alarm,no_alarm 26 | watermeter,43430778,2020-07-17,14:01:01,2020-07-17T14:01:01Z,166.899,162.614,117.73,no_alarm,no_alarm 27 | watermeter,43430778,2020-07-17,14:01:09,2020-07-17T14:01:09Z,166.899,162.614,117.73,no_alarm,no_alarm 28 | watermeter,43430778,2020-07-17,14:01:35,2020-07-17T14:01:35Z,166.899,162.614,117.73,no_alarm,no_alarm 29 | watermeter,43430778,2020-07-17,14:01:43,2020-07-17T14:01:43Z,166.899,162.614,117.73,no_alarm,no_alarm 30 | watermeter,43430778,2020-07-17,14:01:52,2020-07-17T14:01:52Z,166.899,162.614,117.73,no_alarm,No alarm 31 | -------------------------------------------------------------------------------- /data/43430778.json: -------------------------------------------------------------------------------- 1 | {"name": "Wasserz\u00e4hler Haus", "device": "watermeter", "deviceid": "43430778", "date": "2022-02-22", "time": "08:53:37", "total_m3": 347.289, "ratio": 1.02, "m3": {"current": 0.0, "hour": 0.0, "day": 0.063, "month": 6.11, "year": 229.559}, "liter": {"current": 0.0, "hour": 0.0, "day": 63.0, "month": 6110.0, "year": 229559.0}, "last_total": {"hour": "08", "hour_m3": 347.289, "day": "2022-02-22", "day_m3": 347.226, "month": "2022-02", "month_m3": 341.179, "year": "2019-12-31", "year_m3": 117.73}, "wmbusmeter": {"media": "water", "meter": "izar", "name": "watermeter", "id": "18444343", "prefix": "", "serial_number": "000000", "total_m3": 347.289, "last_month_total_m3": 341.179, "last_month_measure_date": "2022-02-01", "remaining_battery_life_y": 11.5, "current_alarms": "no_alarm", "previous_alarms": "no_alarm", "transmit_period_s": 8, "manufacture_year": "0", "timestamp": "2022-02-22T08:53:37Z", "device": "cul", "rssi_dbm": -56}, "alarm": "no_alarm", "last_alarm": "no_alarm", "periode": "2022-02-22", "month": "2022-02", "year": "2022", "timestamp": "2022-02-22T08:53:37Z", "last_update": "2022-02-22 09:53:37.170982", "elapsed_time": "0:00:17", "icon": "mdi:billboard", "unit_of_measurement": "\u33a5", "last_reset": "1970-01-01T00:00:00+00:00", "state_class": "measurement", "device_class": "energy", "version": "1.0.2", "attribution": "Data provided by Peter Siebler", "first_run": false, "data_provider": "MACBOOK-PRO-PETER-WLAN.siebler.home"} -------------------------------------------------------------------------------- /data/default_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Wasserzähler Haus", 3 | "device": "watermeter", 4 | "deviceid": "43430778", 5 | "m3": { "hour": 0.0, "day": 0.0, "month": 0.0, "year": 0.0 }, 6 | "liter": { "hour": 0.0, "day": 0.0, "month": 0.0, "year": 0.0 }, 7 | "alarms": "No alarm", 8 | "previous_alarms": "No alarm", 9 | "periode": "2020-07-15", 10 | "month": "2020-07", 11 | "year": "2020", 12 | "last_month_measure_date": "", 13 | "timestamp": "2020-07-15T05:23:12Z", 14 | "last_update": "2020-07-15T05:23:12Z", 15 | "icon": "mdi:billboard", 16 | "unit_of_measurement": "㎥", 17 | "version": "1.0.0", 18 | "attribution": "Data provided by Peter Siebler" 19 | } 20 | -------------------------------------------------------------------------------- /docs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/.gitkeep -------------------------------------------------------------------------------- /docs/DS_IZAR_RADIO_COMPACT_INDUCTIVE_de_20170906_V2_0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/DS_IZAR_RADIO_COMPACT_INDUCTIVE_de_20170906_V2_0.pdf -------------------------------------------------------------------------------- /docs/DVB-T-DAB-FM- RTL2832U-FC0012 Chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/DVB-T-DAB-FM- RTL2832U-FC0012 Chip.png -------------------------------------------------------------------------------- /docs/MA_IZAR_RADIO_COMPACT_INDUCTIVE_ml_20170529_V2_0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/MA_IZAR_RADIO_COMPACT_INDUCTIVE_ml_20170529_V2_0.pdf -------------------------------------------------------------------------------- /docs/MA_Installation_guide_IZAR_RCi_02_2016_ml_20180314.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/MA_Installation_guide_IZAR_RCi_02_2016_ml_20180314.pdf -------------------------------------------------------------------------------- /docs/RB3B_DVBT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/RB3B_DVBT.png -------------------------------------------------------------------------------- /docs/SDR_STICK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/SDR_STICK.png -------------------------------------------------------------------------------- /docs/build-rtl-wmbus.md: -------------------------------------------------------------------------------- 1 | # Builds and runs rtl-wmbus on GNU/Linux 2 | 3 | The primary purpose of rtl-wmbus is experimenting with digital signal processing and software radio. rtl-wmbus can be used on resource constrained devices such Raspberry Pi Zero or Raspberry PI B+ overclocked to 1GHz. 4 | 5 | rtl-wmbus is a software defined receiver for Wireless-M-Bus. It is written in plain C and uses RTL-SDR (https://github.com/osmocom/rtl-sdr) to interface with RTL2832-based hardware. 6 | 7 | The Osmocom RTL-SDR library must be installed before you can build rtl-wmbus. See http://sdr.osmocom.org/trac/wiki/rtl-sdr for more information. 8 | 9 | To install rtl-wmbus, download, unpack the source code and go to the top level directory: 10 | 11 | ```bash 12 | # $ git clone https://github.com/xaelsouth/rtl-wmbus.git 13 | $ git clone https://github.com/weetmuts/rtl-wmbus.git 14 | $ cd rtl-wmbus 15 | # $ make 16 | # $ make debug # (no optimization at all, with debug options) 17 | $ make release # (-O3 optimized version, without any debugging options 18 | $ cp rtl-wmbus/build/rtl_wmbus /usr/bin/rtl_wmbus 19 | 20 | ``` 21 | 22 | ## Test rtl-wmbus 23 | 24 | ```bash 25 | $ ls -l /dev/rtlsdr* 26 | >> lrwxrwxrwx 1 root root 15 Jul 19 05:59 /dev/rtlsdr_5 -> bus/usb/001/004 27 | 28 | $ cd build 29 | $ rtl_sdr -f 868.95M -s 1.6e6 - | rtl_wmbus 30 | $ rtl_sdr -f 868.95M -s 1600000 - 2 | rtl_wmbus 31 | $ rtl_sdr -f 868.95M -s 1.6e6 - 2>/dev/null | rtl_wmbus 32 | 33 | >>> Results 34 | Found 1 device(s): 35 | 0: Realtek, RTL2838UHIDIR, SN: 00000001 36 | 37 | Using device 0: Generic RTL2832U OEM 38 | Found Fitipower FC0012 tuner 39 | Sampling at 1600000 S/s. 40 | Tuned to 868950000 Hz. 41 | Tuner gain set to automatic. 42 | Reading samples in async mode... 43 | Allocating 15 zero-copy buffers 44 | T1;0;0;2020-07-19 05:28:57.000;46;95;43410778;0x1944a511780741434418ff411a0013109684c3a89f7017569381 45 | T1;0;0;2020-07-19 05:28:59.000;53;107;FF430778;0x1944a511780743ffff18a2611a001312f3e9669a7e9d9c8381d2 46 | T1;0;0;2020-07-19 05:29:00.000;61;60;FFFF0785;0x19ff24238507ffffff18a261ffffffff1cbe74ff32ffff72ffff 47 | T1;0;0;2020-07-19 05:29:05.000;59;100;43FF0778;0x1944a5117807ff43ffffa251ff00131081abff03bea3ce8d8a83 48 | T1;0;0;2020-07-19 05:29:08.000;69;77;43430778;0x1944a51178074343ffffa2711a001312e4c62f315f4e455898d0 49 | T1;0;0;2020-07-19 05:29:09.000;34;66;FFFFFFFF;0x1944ff23ffffffffff18a2ffffffff11ffff3dffffff70a9ffff 50 | T1;0;0;2020-07-19 05:29:14.000;51;84;43410778;0x1944a511780741434418a261ff001310b8da50fedcd7a4e0a184 51 | T1;0;0;2020-07-19 05:29:17.000;46;179;43FF0778;0x1944a5117807ff4344ffa2011a001312810ad360ba754859d7dd 52 | T1;0;0;2020-07-19 05:29:18.000;42;68;FF8907FF;0x19ffffffff0789ffff18ff01ffffff116b5dfffff664ffffffff 53 | T1;0;0;2020-07-19 05:29:22.000;48;52;43FF0778;0x19ffa5117807ff434418a2711a001310aff51955fd04ffffff01 54 | T1;0;0;2020-07-19 05:29:26.000;53;169;43430778;0x1944a511780743434418a2111a00131296259acb9bff9182cedf 55 | T1;0;0;2020-07-19 05:29:27.000;45;61;FFFF07FF;0x19ff2423ff07ffff4418a2ffff0013117cffffbbd7b7ffffffff 56 | T1;1;1;2020-07-19 05:29:31.000;57;167;43410778;0x1944a511780741434418a2011a001310ca39e504183f703af78b 57 | T1;0;0;2020-07-19 05:29:34.000;67;135;43430778;0x1944a511780743434418a221ff001312af544036f9d2fbefe5d8 58 | T1;0;0;2020-07-19 05:29:36.000;40;80;FFFF07FF;0x1944ffffff07ffffffffa2210600ffffffffffffffc3ffffffff 59 | T1;0;0;2020-07-19 05:29:40.000;49;178;43410778;0x1944a511780741434418a211ffff1310dd16acaf39eca9e1ee89 60 | ``` 61 | 62 | 63 | 64 | ## For more information see: 65 | 66 | ```txt 67 | https://github.com/xaelsouth/rtl-wmbus 68 | 69 | ## Adjust length byte after DLL CRC:s are removed. 70 | When trimming away the crc bytes, update the first len byte. 71 | 72 | Previously wmbusmeters was not so picky, and it worked anyway, 73 | but now wmbusmeters actually check the internal payload crc:s and 74 | other lengths. So an incorrect len byte fails. 75 | 76 | The hardware dongles like im871a, amb8465 do update the 77 | len byte as well. 78 | 79 | https://github.com/weetmuts/rtl-wmbus 80 | ``` 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/d1Mini868Mhz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/d1Mini868Mhz.png -------------------------------------------------------------------------------- /docs/d1min_cc1101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/d1min_cc1101.png -------------------------------------------------------------------------------- /docs/diehl_metering.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/diehl_metering.jpg -------------------------------------------------------------------------------- /docs/esphome-watermeter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/esphome-watermeter.png -------------------------------------------------------------------------------- /docs/ha-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/ha-card.png -------------------------------------------------------------------------------- /docs/ha-card2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/ha-card2.png -------------------------------------------------------------------------------- /docs/homeassistant/card02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/homeassistant/card02.png -------------------------------------------------------------------------------- /docs/homeassistant/card1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/homeassistant/card1.png -------------------------------------------------------------------------------- /docs/homeassistant/config/input_numbers/water.yaml: -------------------------------------------------------------------------------- 1 | ## #################################################################################################### 2 | ## calulation for a month 3 | ## (m3_water * cost_m3_wasser) + (m3_water * cost_m3abwasser) + cost_watermeterfee + cost_waterbasefee 4 | ## #################################################################################################### 5 | cost_m3_wasser: 6 | name: Wasser €/m3 7 | icon: mdi:currency-eur 8 | initial: 5.4176 9 | unit_of_measurement: "€" 10 | min: 5.00 11 | max: 10.00 12 | mode: box 13 | 14 | cost_m3wasser: 15 | name: Wasserbezugsgebühr 16 | icon: mdi:currency-eur 17 | initial: 0.88 18 | unit_of_measurement: "€" 19 | min: 0.80 20 | max: 1.50 21 | mode: box 22 | 23 | cost_m3abwasser: 24 | name: Kanalbenützungsgebühr 25 | icon: mdi:currency-eur 26 | initial: 3.38 27 | unit_of_measurement: "€" 28 | min: 3.00 29 | max: 5.00 30 | mode: box 31 | 32 | cost_watermeterfee: 33 | name: Zählermiete / Monat 34 | icon: mdi:currency-eur 35 | initial: 2.157 36 | unit_of_measurement: "€" 37 | min: 2.000 38 | max: 3.500 39 | mode: box 40 | 41 | cost_waterbasefee: 42 | name: Wassergrundgebühr / Monat 43 | icon: mdi:currency-eur 44 | initial: 4.917 45 | unit_of_measurement: "€" 46 | min: 4.800 47 | max: 6.500 48 | mode: box 49 | 50 | max_m3_day: 51 | name: Wasser m3 pro Tag 52 | icon: mdi:counter 53 | initial: 0.60 54 | unit_of_measurement: "\u33A5" 55 | min: .200 56 | max: 3.00 57 | mode: box 58 | 59 | max_m3_month: 60 | name: Wasser m3 pro Monat 61 | icon: mdi:counter 62 | initial: 15.00 63 | unit_of_measurement: "\u33A5" 64 | min: 5.00 65 | max: 20.00 66 | mode: box 67 | 68 | max_m3_year: 69 | name: Wasser m3 pro Jahr 70 | icon: mdi:counter 71 | initial: 102.000 72 | unit_of_measurement: "\u33A5" 73 | min: 80.00 74 | max: 200.00 75 | mode: box 76 | -------------------------------------------------------------------------------- /docs/homeassistant/config/sensor/smartmeter-watercosts.yaml: -------------------------------------------------------------------------------- 1 | 2 | - platform: template 3 | 4 | sensors: 5 | 6 | ## calculate the water costs 7 | 8 | water_cost_current: 9 | friendly_name: "Wasser aktuell" 10 | value_template: >- 11 | {{ (states("sensor.wasserverbrauch")|float * states.input_number.cost_m3_wasser.state|float)|round(2)}} 12 | unit_of_measurement: "€" 13 | 14 | water_cost_hour: 15 | friendly_name: "Wasser pro Stunde" 16 | value_template: >- 17 | {{ (states("sensor.wasser_pro_stunde")|float * states.input_number.cost_m3_wasser.state|float)|round(2)}} 18 | unit_of_measurement: "€" 19 | 20 | water_cost_day: 21 | friendly_name: "Wasser pro Tag" 22 | value_template: >- 23 | {{ (states("sensor.wasser_pro_tag")|float * states.input_number.cost_m3_wasser.state|float)|round(2)}} 24 | unit_of_measurement: "€" 25 | 26 | water_cost_month: 27 | friendly_name: "Wasser pro Monat" 28 | value_template: >- 29 | {{ (states("sensor.wasser_pro_monat")|float * states.input_number.cost_m3_wasser.state|float)|round(2)}} 30 | unit_of_measurement: "€" 31 | 32 | water_cost_jahr: 33 | friendly_name: "Wasser pro Jahr" 34 | value_template: >- 35 | {{ (states("sensor.wasser_pro_jahr")|float * states.input_number.cost_m3_wasser.state|float)|round(2)}} 36 | unit_of_measurement: "€" 37 | 38 | -------------------------------------------------------------------------------- /docs/homeassistant/details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/homeassistant/details.png -------------------------------------------------------------------------------- /docs/homeassistant/lovelace/cards/smartmeter-water/card-water-days.yaml: -------------------------------------------------------------------------------- 1 | type: "custom:mini-graph-card" 2 | style: |- 3 | ha-card{ 4 | transform: scale(0.96); 5 | background-size: 100% 100%; 6 | } 7 | entities: 8 | - entity: sensor.wasser_liter_tag 9 | name: Tagesverbrauch 10 | aggregate_func: last 11 | state_adaptive_color: true 12 | 13 | name: Wasser / Tag _ 14 | font_size: 85 15 | font_size_header: 18 16 | align_icon: left 17 | align_state: center 18 | align_header: left 19 | height: 186 20 | hours_to_show: 168 21 | hour24: true 22 | group_by: date 23 | unit: "Liter / Tag" 24 | icon: mdi:waves 25 | line_width: 1 26 | more_info: true 27 | lower_bound: 0.00 28 | upper_bound: 400.00 29 | show: 30 | icon_adaptive_color: true 31 | name_adaptive_color: true 32 | extrema: true 33 | graph: bar 34 | 35 | color_thresholds: 36 | - value: 50 37 | color: "#2196F3" 38 | - value: 100 39 | color: "#0D47A1" 40 | - value: 200 41 | color: "#1976D2" 42 | - value: 300 43 | color: "#42A5F5" 44 | - value: 400 45 | color: "#90CAF9" -------------------------------------------------------------------------------- /docs/homeassistant/lovelace/cards/smartmeter-water/card-water-overview.yaml: -------------------------------------------------------------------------------- 1 | type: "custom:mini-graph-card" 2 | style: |- 3 | ha-card{ 4 | transform: scale(0.96); 5 | background-size: 100% 100%; 6 | } 7 | entities: 8 | - entity: sensor.wasser_liter_h 9 | name: Aktuell 10 | aggregate_func: max 11 | name: Wasser / Stunde _ 12 | font_size: 85 13 | font_size_header: 18 14 | align_icon: left 15 | align_state: center 16 | align_header: left 17 | height: 186 18 | hours_to_show: 48 19 | hour24: true 20 | group_by: hour 21 | unit: "Liter / h" 22 | icon: mdi:waves 23 | line_width: 1 24 | more_info: true 25 | # lower_bound: 0.00 26 | # upper_bound: 50.00 27 | show: 28 | icon_adaptive_color: true 29 | name_adaptive_color: true 30 | name: true 31 | icon: true 32 | state: true 33 | fill: fade 34 | legend: true 35 | extrema: true 36 | graph: bar 37 | color_thresholds: 38 | - value: 5 39 | color: "#2196F3" 40 | - value: 10 41 | color: "#0D47A1" 42 | - value: 15 43 | color: "#1976D2" 44 | - value: 20 45 | color: "#42A5F5" 46 | - value: 30 47 | color: "#90CAF9" -------------------------------------------------------------------------------- /docs/homeassistant/lovelace/cards/smartmeter-water/card-water-usage.yaml: -------------------------------------------------------------------------------- 1 | ## ################################# 2 | ## Card water usage 3 | ## ################################# 4 | type: "custom:bar-card" 5 | entities: 6 | - entity: sensor.wasser_liter_h 7 | name: Jetzt 8 | min: 0.0 9 | max: 100.0 10 | - entity: sensor.wasser_liter_tag 11 | name: Heute 12 | min: 0.0 13 | max: 420.0 14 | - entity: sensor.wasser_liter_monat 15 | name: Monat 16 | min: 0.0 17 | max: 5200.0 18 | - entity: sensor.wasser_liter_jahr 19 | name: Jahr 20 | min: 0.0 21 | max: 120000.0 22 | title: Übersicht Wasserverbrauch 23 | title_icon: mdi:waves 24 | direction: up 25 | height: 150px 26 | width: 75% 27 | stack: horizontal 28 | animation: auto 29 | positions: 30 | icon: inside 31 | indicator: inside 32 | name: outside 33 | title: outside 34 | style: | 35 | ha-card{ 36 | transform: scale(0.96); 37 | background-size: 100% 100%; 38 | } 39 | .card-header{ 40 | padding: 6px 20px; 41 | font-size: 1.4em; 42 | text-align: left; 43 | color: #007aff; 44 | } 45 | .graph__legend { flex-wrap: nowrap; } 46 | #states { padding: 24px 24px; } 47 | bar-card-value { font-size: 0.9em } 48 | bar-card-current, bar-card-backgroundbar, bar-card-currentbar { 49 | border-radius: 0 0 1.6em 1.6em; 50 | } 51 | -------------------------------------------------------------------------------- /docs/homeassistant/mqtt-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Wasserz\u00e4hler Haus", 3 | "device": "watermeter", 4 | "deviceid": "43430778", 5 | "date": "2021-03-13", 6 | "time": "13:45:46", 7 | "total_m3": 234.489, 8 | "m3": { 9 | "current": 0.0, 10 | "hour": 0.028, 11 | "day": 0.204, 12 | "month": 3.64, 13 | "year": 20.216 14 | }, 15 | "liter": { 16 | "current": 0.0, 17 | "hour": 28.0, 18 | "day": 204.0, 19 | "month": 3640.0, 20 | "year": 20216.0 21 | }, 22 | "last_total": { 23 | "hour": "13", 24 | "hour_m3": 234.461, 25 | "day": "2021-03-13", 26 | "day_m3": 234.285, 27 | "month": "2021-03", 28 | "month_m3": 230.849, 29 | "year": "2021", 30 | "year_m3": 214.273 31 | }, 32 | "alarm": "no_alarm", 33 | "last_alarm": "no_alarm", 34 | "periode": "2021-03-13", 35 | "month": "2021-03", 36 | "year": "2021", 37 | "timestamp": "2021-03-13T13:45:46Z", 38 | "last_update": "2021-03-13 14:45:46.914795", 39 | "elapsed_time": "0:00:17", 40 | "icon": "mdi:billboard", 41 | "unit_of_measurement": "\u33a5", 42 | "version": "1.0.0", 43 | "attribution": "Data provided by Peter Siebler", 44 | "data_provider": "smarthome.siebler.home" 45 | } 46 | -------------------------------------------------------------------------------- /docs/homeassistant/view_watermeter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/homeassistant/view_watermeter.png -------------------------------------------------------------------------------- /docs/homeassistant/water_barcard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/homeassistant/water_barcard.png -------------------------------------------------------------------------------- /docs/homeassistant/water_homekitpanel_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/homeassistant/water_homekitpanel_card.png -------------------------------------------------------------------------------- /docs/liter-pro-stunde.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/liter-pro-stunde.png -------------------------------------------------------------------------------- /docs/logging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/logging.png -------------------------------------------------------------------------------- /docs/nanoCUL868.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/nanoCUL868.png -------------------------------------------------------------------------------- /docs/nanocul_v3/nanocul.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/nanocul_v3/nanocul.jpg -------------------------------------------------------------------------------- /docs/rpw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/rpw.png -------------------------------------------------------------------------------- /docs/rtl-sdr4linux_quickstartguidev20.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/rtl-sdr4linux_quickstartguidev20.pdf -------------------------------------------------------------------------------- /docs/sampedata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Wasserz\u00e4hler Haus", 3 | "device": "watermeter", 4 | "deviceid": "43430778", 5 | "date": "2020-07-15", 6 | "time": "13:54:45", 7 | "total_m3": 166.426, 8 | "m3": { 9 | "current": 0.0, 10 | "hour": 0.004, 11 | "day": 1.029, 12 | "month": 3.812, 13 | "year": 48.696 14 | }, 15 | "liter": { 16 | "current": 0.0, 17 | "hour": 4.0, 18 | "day": 1029.0, 19 | "month": 3812.0, 20 | "year": 48696.0 21 | }, 22 | "last_total": { 23 | "hour": "13", 24 | "hour_m3": 166.422, 25 | "day": "2020-07-15", 26 | "day_m3": 165.397, 27 | "month": "2020-07", 28 | "month_m3": 162.614, 29 | "year": "2020-01-01", 30 | "year_m3": 117.73 31 | }, 32 | "alarm": "no_alarm", 33 | "last_alarm": "no_alarm", 34 | "periode": "2020-07-15", 35 | "month": "2020-07", 36 | "year": "2020", 37 | "timestamp": "2020-07-15T13:54:45Z", 38 | "last_update": "2020-07-15 15:54:45.287626", 39 | "elapsed_time": "0:00:09", 40 | "icon": "mdi:billboard", 41 | "unit_of_measurement": "\u33a5", 42 | "version": "1.0.0", 43 | "attribution": "Data provided by Peter Siebler", 44 | "data_provider": "ubuntu server" 45 | } -------------------------------------------------------------------------------- /docs/top-nanocul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/top-nanocul.png -------------------------------------------------------------------------------- /docs/top-rtlsdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/docs/top-rtlsdr.png -------------------------------------------------------------------------------- /docs/wmbusdata.json: -------------------------------------------------------------------------------- 1 | { 2 | "media": "water", 3 | "meter": "izar", 4 | "name": "watermeter", 5 | "id": "1231150", 6 | "total_m3": 166.625, 7 | "last_month_total_m3": 162.614, 8 | "last_month_measure_date": "2020-07-01", 9 | "remaining_battery_life_y": 13, 10 | "current_alarms": "no_alarm", 11 | "previous_alarms": "no_alarm", 12 | "timestamp": "2020-07-16T11:32:38Z" 13 | } -------------------------------------------------------------------------------- /docs/wmbusmeters-nano_cul.md: -------------------------------------------------------------------------------- 1 | # wmbusmeters version: 0.9.34 with NANO-CUL (mbus) 868 Mhz 2 | 3 | ![nano CUL 868 ](nanoCUL868.png) 4 | 5 | 6 | 7 | NANO-CUL (mbus) 868 is a lot easier to use because it only requires `wmbusmeters`. 8 | The resources (memory) required are also less compared to the variant with RTL-SDR and rtl-wmbus. 9 | #### RTL-SDR and rtl-wmbus: 32 % CPU 10 | ![nano CUL 868 ](top-rtlsdr.png) 11 |
12 | The tests also show that the signal processing is better and thus the range for receiving the data is increased. 13 | #### NANO-CUL (mbus) 868: 0.7 % CPU ! 14 | ![nano CUL 868 ](top-nanocul.png) 15 | 16 | `nano CUL 868 mit Externer Magnetfußantenne` , see: https://www.smart-home-komponente.de/ 17 | 18 | ## Update system 19 | 20 | The following is required before installation: 21 | 22 | ```bash 23 | $ sudo apt-get update 24 | $ sudo apt-get install build-essential libncurses-dev cmake automake make 25 | $ sudo apt-get install -y mosquitto mosquitto-clients librtlsdr-dev libxml2-dev 26 | ``` 27 | 28 | ## Build wmbusmeters 29 | 30 | The program receives and decodes C1,T1 or S1 telegrams (using the wireless mbus protocol) to acquire utility meter readings. The readings can then be published using MQTT, curled to a REST api, inserted into a database or stored in a log file. 31 | 32 | ```bash 33 | $ git clone https://github.com/weetmuts/wmbusmeters.git 34 | $ cd wmbusmeters 35 | $ make && make test 36 | 37 | $ make install 38 | 39 | ## optional, only if debuging 40 | $ make DEBUG=true 41 | 42 | $ lsusb 43 | ## --> Bus 001 Device 004: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC 44 | 45 | $ ls -l /dev/serial/by-id 46 | ## --> lrwxrwxrwx 1 root root 13 Feb 8 09:33 usb-SHK_NANO_CUL_868-if00-port0 -> ../../ttyUSB0 47 | 48 | $ ls -l /dev/ttyUSB0 49 | ## >> wmbusmeters 188, 0 Jul 21 13:50 ttyUSB0 50 | 51 | $ dmesg | grep ttyUSB0 52 | ##[ 491.198770] usb 2-5: FTDI USB Serial Device converter now attached to ttyUSB0 53 | ##[ 2413.835006] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now ##disconnected from ttyUSB0 54 | ##[ 2419.879307] usb 2-5: FTDI USB Serial Device converter now attached to ttyUSB0 55 | 56 | 57 | # get the id for the watermeter 58 | $ wmbusmeters --listento=t1 /dev/ttyUSB0 59 | 60 | ``` 61 | 62 | Result from the test: `wmbusmeters --listento=t1 /dev/ttyUSB0` 63 | 64 | ```verilog 65 | Results: 66 | 67 | No meters configured. Printing id:s of all telegrams heard! 68 | 69 | Received telegram from: 43410778 70 | manufacturer: (DME) DIEHL Metering, Germany 71 | device type: Pressure meter 72 | Received telegram from: 15300778 73 | manufacturer: (DME) DIEHL Metering, Germany 74 | device type: A/D converter 75 | Received telegram from: 43430778 76 | manufacturer: (DME) DIEHL Metering, Germany 77 | device type: Pressure meter 78 | ``` 79 | 80 | 81 | 82 | ## Debug and test installed wmbusmeters 83 | 84 | ```bash 85 | wmbusmeters --listento=t1 --debug --logtelegrams /dev/ttyUSB0 diehl izar 43410778 NOKEY 86 | 87 | >> (izar) 0a: a2 tpl-ci-field (Mfct specific) 88 | diehl 43410778 87.511 m3 84.654 m3 2020-07-01 13 y no_alarm no_alarm 2020-07-21 14:08.40 89 | 90 | 91 | ``` 92 | 93 | 94 | 95 | ## Configuration wmbusmeters 96 | 97 | Check the config file `nano /etc/wmbusmeters.conf` and edit the device to point to your dongle. 98 | 99 | ```ini 100 | loglevel=normal 101 | device=/dev/ttyUSB0 102 | logtelegrams=true 103 | format=json 104 | meterfiles=/var/log/wmbusmeters/meter_readings 105 | meterfilesaction=overwrite 106 | meterfilesnaming=name 107 | meterfilestimestamp=hour 108 | logfile=/var/log/wmbusmeters/wmbusmeters.log 109 | shell=/usr/bin/mosquitto_pub -h mbs.siebler.home -p 1883 -u "username" -P "password" -t tele/testsensor/verbrauch -m "$METER_JSON" 110 | ``` 111 | 112 | 113 | 114 | Then add a meter file in `nano /etc/wmbusmeters.d/diehl` 115 | 116 | ```ini 117 | name=watermeter 118 | type=izar 119 | id=43430778 120 | key= 121 | ``` 122 | 123 | 124 | 125 | ## Service wmbusmeters 126 | 127 | ```bash 128 | $ sudo systemctl daemon-reload 129 | 130 | $ systemctl start wmbusmeters 131 | $ systemctl status wmbusmeters 132 | $ systemctl enable wmbusmeters 133 | $ systemctl stop wmbusmeters 134 | $ systemctl restart wmbusmeters 135 | 136 | ``` 137 | 138 | -------------------------------------------------------------------------------- /esphome/.gitignore: -------------------------------------------------------------------------------- 1 | # Gitignore settings for ESPHome 2 | # This is an example and may include too much for your use-case. 3 | # You can modify this file to suit your needs. 4 | /.esphome/ 5 | /secrets.yaml 6 | -------------------------------------------------------------------------------- /esphome/custom_components/backup/README.md: -------------------------------------------------------------------------------- 1 | # Backup 2 | 3 | Save your ESPHome device configuration in firmware and and recover it if you lost source files. Just download it from `http://yourdevice.local/config.yaml`. 4 | 5 | > WARNING: You should backup your all your files, this solution only for emergency purpose. I am not responsible for the loss or inability to recover data. 6 | 7 | > WARNING: Stored configuration is the same as shown by `esphome config` command. It is fully worked but not the same as your original sources. 8 | 9 | > WARNING: Command line substitutions, custom components and includes are not supported yet! 10 | 11 | The configuration is very simple. Look at a sample below: 12 | ```yaml 13 | # Full example of configuration entry 14 | ... 15 | external_components: 16 | - source: 17 | type: git 18 | url: https://github.com/zdzichu6969/esphome_components 19 | components: [ backup ] 20 | refresh: 0s 21 | ... 22 | backup: 23 | auth: 24 | username: !secret web_username 25 | password: !secret web_password 26 | force_update: false 27 | ``` 28 | 29 | ## Configuration variables: 30 | * **auth** (*Optional*): Enables basic authentication with username and password. 31 | * **username** (**Required**, string): The username to use for authentication. 32 | * **password** (**Required**, string): The password to check for authentication. 33 | * **force_update** (*Optional*, boolean): Unnecessary but might be needed when you changes in separated files are not detected properly. Default is False. 34 | -------------------------------------------------------------------------------- /esphome/custom_components/backup/__init__.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | from gzip import GzipFile 3 | from pathlib import Path 4 | import logging 5 | import esphome.codegen as cg 6 | import esphome.config_validation as cv 7 | from esphome.config import strip_default_ids 8 | from esphome.cpp_generator import ArrayInitializer 9 | from esphome.yaml_util import dump, load_yaml 10 | from esphome.core import CORE, coroutine_with_priority, ID 11 | from esphome.components import web_server_base 12 | from esphome.components.web_server_base import CONF_WEB_SERVER_BASE_ID 13 | from esphome.const import ( 14 | CONF_AUTH, 15 | CONF_FORCE_UPDATE, 16 | CONF_ID, 17 | CONF_PASSWORD, 18 | CONF_RAW_DATA_ID, 19 | CONF_USERNAME, 20 | ) 21 | 22 | _LOGGER = logging.getLogger(__name__) 23 | 24 | AUTO_LOAD = ["web_server_base", "web_server"] 25 | 26 | CONF_BACKUP = "backup" 27 | 28 | backup_ns = cg.esphome_ns.namespace("backup") 29 | Backup = backup_ns.class_("Backup", cg.Component) 30 | 31 | CONFIG_SCHEMA = cv.Schema( 32 | { 33 | cv.GenerateID(): cv.declare_id(Backup), 34 | cv.GenerateID(CONF_WEB_SERVER_BASE_ID): cv.use_id( 35 | web_server_base.WebServerBase 36 | ), 37 | cv.Optional(CONF_AUTH): cv.Schema( 38 | { 39 | cv.Required(CONF_USERNAME): cv.string_strict, 40 | cv.Required(CONF_PASSWORD): cv.string_strict, 41 | } 42 | ), 43 | cv.Optional(CONF_FORCE_UPDATE, default=False): cv.boolean, 44 | } 45 | ).extend(cv.COMPONENT_SCHEMA) 46 | 47 | 48 | def _dump_config(): 49 | return dump(strip_default_ids(load_yaml(CORE.config_path))) 50 | 51 | 52 | @coroutine_with_priority(40.0) 53 | async def to_code(config): 54 | paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) 55 | 56 | var = cg.new_Pvariable(config[CONF_ID], paren) 57 | await cg.register_component(var, config) 58 | 59 | if CONF_AUTH in config: 60 | username = config[CONF_AUTH][CONF_USERNAME] 61 | if username: 62 | cg.add(var.set_username(username)) 63 | password = config[CONF_AUTH][CONF_PASSWORD] 64 | if password: 65 | cg.add(var.set_password(password)) 66 | 67 | gz_io = BytesIO() 68 | with GzipFile( 69 | fileobj=gz_io, 70 | mode="wb", 71 | compresslevel=9, 72 | mtime=None 73 | if config[CONF_FORCE_UPDATE] 74 | else Path(CORE.config_path).stat().st_mtime, 75 | ) as f: 76 | f.write(bytes(_dump_config(), encoding="utf8")) 77 | 78 | gz_config = gz_io.getvalue() 79 | 80 | arr = cg.progmem_array( 81 | ID( 82 | "backup_data_43c31a8938664f3a97597d916cb5c2ba", 83 | is_declaration=True, 84 | type=cg.uint8, 85 | ), 86 | ArrayInitializer(*[o for o in gz_config]), 87 | ) 88 | cg.add(var.set_config(arr, len(gz_config))) 89 | 90 | _LOGGER.info(f"Backup config will take: {len(gz_config)} bytes") 91 | -------------------------------------------------------------------------------- /esphome/custom_components/backup/backup.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "esphome/core/log.h" 3 | #include "esphome/core/application.h" 4 | #include "esphome/core/util.h" 5 | #include "esphome/components/json/json_util.h" 6 | 7 | #include "StreamString.h" 8 | 9 | #include 10 | 11 | #include "backup.h" 12 | 13 | namespace esphome { 14 | namespace backup { 15 | 16 | static const char *const TAG = "backup"; 17 | static const char *const URL = "/config.yaml"; 18 | 19 | void Backup::setup() { 20 | ESP_LOGCONFIG(TAG, "Setting up backup handler..."); 21 | this->base_->init(); 22 | this->base_->get_server()->on(URL, HTTP_GET, [this](AsyncWebServerRequest *request) { 23 | if (this->using_auth() && !request->authenticate(this->username_, this->password_)) { 24 | return request->requestAuthentication(); 25 | } 26 | auto response = request->beginResponse_P(200, "plain/text;charset=UTF-8", this->data_, this->size_); 27 | response->addHeader("Content-Encoding", "gzip"); 28 | request->send(response); 29 | }); 30 | } 31 | 32 | void Backup::dump_config() { 33 | ESP_LOGCONFIG(TAG, "Backup:"); 34 | ESP_LOGCONFIG(TAG, " URL path is %s", URL); 35 | if (this->using_auth()) { 36 | ESP_LOGCONFIG(TAG, " Basic authentication enabled"); 37 | } 38 | } 39 | 40 | } // namespace backup 41 | } // namespace esphome 42 | -------------------------------------------------------------------------------- /esphome/custom_components/backup/backup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/component.h" 4 | #include "esphome/core/controller.h" 5 | #include "esphome/components/web_server_base/web_server_base.h" 6 | 7 | #include 8 | 9 | namespace esphome { 10 | namespace backup { 11 | 12 | class Backup : public Component { 13 | public: 14 | explicit Backup(web_server_base::WebServerBase *base) : base_(base) {} 15 | 16 | void setup() override; 17 | void dump_config() override; 18 | float get_setup_priority() const override { return setup_priority::WIFI - 1.0f; } 19 | 20 | void set_config(const uint8_t *data, size_t size) { 21 | this->data_ = data; 22 | this->size_ = size; 23 | } 24 | 25 | void set_username(const char *username) { this->username_ = username; } 26 | 27 | void set_password(const char *password) { this->password_ = password; } 28 | 29 | bool using_auth() { return this->username_ != nullptr && this->password_ != nullptr; } 30 | 31 | protected: 32 | web_server_base::WebServerBase *base_; 33 | const uint8_t *data_{nullptr}; 34 | size_t size_{0}; 35 | const char *username_{nullptr}; 36 | const char *password_{nullptr}; 37 | }; 38 | 39 | } // namespace backup 40 | } // namespace esphome 41 | -------------------------------------------------------------------------------- /esphome/custom_components/crash_info/README.md: -------------------------------------------------------------------------------- 1 | # Crash Info 2 | 3 | An ESP8266 remote crash detector. 4 | With enabled indicator you can monitor crashes right from your Home Assistant. 5 | 6 | ## Advanced usage 7 | Connect to you ESP8266 and find crash backtrace information in the log. 8 | Copy stack frames and decode with `xtensa-lx106-elf-addr2line -aipfC -e $elf ...` command. 9 | 10 | > By default crash information stored in RTC memory and do not survive power loss. You can change this bahaviour by store_in_flash by be carefull it is may not work properly due dynamic memory usage in this procedure. 11 | 12 | ```yaml 13 | # Example configuration entry. 14 | ... 15 | external_components: 16 | - source: 17 | type: git 18 | url: https://github.com/zdzichu6969/esphome_components 19 | components: [ crash_info ] 20 | refresh: 0s 21 | ... 22 | crash_info: 23 | id: crash_info_obj 24 | # Optional, uint32. The number of stack frames to be saved. 25 | max_stack_frames_size: 10 26 | # Optional, uint32. Minimum address of stack frame to be saved. Default: 0x40000000. 27 | min_stack_frames_addr: 0x40000000 28 | # Optional, uint32. Maximum address of stack frame to be saved. Default: 0x50000000. 29 | max_stack_frames_addr: 0x50000000 30 | # Optional, binary_sensor. Crash indicator. 31 | indicator: 32 | name: $name Crash state 33 | # Optional, boolean. Store backtrace in FLASH or RTC. Default: false. 34 | store_in_flash: false 35 | # Optional, uint. Break line after this number of frames. Default: 4 36 | frames_in_line: 4 37 | 38 | # Add button to reset state of crash. 39 | button: 40 | - platform: template 41 | name: $name Reset crash state 42 | on_press: 43 | lambda: id(crash_info_obj).reset(); 44 | 45 | # Add sntp or homeassistant time platform to enable saving crash time. 46 | time: 47 | - platform: sntp 48 | timezone: UTC-3 49 | id: time_sntp_obj 50 | 51 | ``` 52 | -------------------------------------------------------------------------------- /esphome/custom_components/crash_info/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import esphome.codegen as cg 3 | import esphome.config_validation as cv 4 | from esphome.core import CORE 5 | from esphome.cpp_types import Component 6 | from esphome.components import binary_sensor 7 | from esphome.const import ( 8 | DEVICE_CLASS_PROBLEM, 9 | ENTITY_CATEGORY_DIAGNOSTIC, 10 | PLATFORM_ESP8266, 11 | CONF_ID, 12 | ) 13 | 14 | _LOGGER = logging.getLogger(__name__) 15 | 16 | ESP_PLATFORMS = [PLATFORM_ESP8266] 17 | AUTO_LOAD = ["binary_sensor"] 18 | 19 | CONF_MAX_STACK_FRAMES_SIZE = "max_stack_frames_size" 20 | CONF_MIN_STACK_FRAMES_ADDR = "min_stack_frames_addr" 21 | CONF_MAX_STACK_FRAMES_ADDR = "max_stack_frames_addr" 22 | CONF_INDICATOR = "indicator" 23 | CONF_STORE_IN_FLASH = "store_in_flash" 24 | CONF_STORE_FREE_HEAP = "store_free_heap" 25 | CONF_FRAMES_IN_LINE = "frames_in_line" 26 | 27 | MAX_STACK_FRAMES = 120 28 | 29 | crash_info_ns = cg.esphome_ns.namespace("crash_info") 30 | CrashInfo = crash_info_ns.class_("CrashInfo", Component) 31 | 32 | CONFIG_SCHEMA = cv.Schema( 33 | { 34 | cv.GenerateID(): cv.declare_id(CrashInfo), 35 | cv.Optional(CONF_MAX_STACK_FRAMES_SIZE, default=10): cv.All( 36 | cv.positive_int, cv.int_range(4, MAX_STACK_FRAMES) 37 | ), 38 | cv.Optional(CONF_MIN_STACK_FRAMES_ADDR, default=0x40000000): cv.All( 39 | cv.positive_int, cv.int_range(min=1, max=0x70000000) 40 | ), 41 | cv.Optional(CONF_MAX_STACK_FRAMES_ADDR, default=0x50000000): cv.All( 42 | cv.positive_int, cv.int_range(min=1, max=0x70000000) 43 | ), 44 | cv.Optional(CONF_INDICATOR): binary_sensor.binary_sensor_schema( 45 | device_class=DEVICE_CLASS_PROBLEM, 46 | entity_category=ENTITY_CATEGORY_DIAGNOSTIC, 47 | ), 48 | cv.Optional(CONF_STORE_IN_FLASH, default=False): cv.boolean, 49 | cv.Optional(CONF_STORE_FREE_HEAP, default=False): cv.boolean, 50 | cv.Optional(CONF_FRAMES_IN_LINE, default=4): cv.All( 51 | cv.positive_int, cv.int_range(min=1, max=MAX_STACK_FRAMES) 52 | ), 53 | } 54 | ) 55 | 56 | 57 | async def to_code(config): 58 | var = cg.new_Pvariable(config[CONF_ID]) 59 | await cg.register_component(var, config) 60 | 61 | if CONF_INDICATOR in config: 62 | conf = config[CONF_INDICATOR] 63 | sens = cg.new_Pvariable(conf[CONF_ID]) 64 | await binary_sensor.register_binary_sensor(sens, conf) 65 | cg.add(var.set_indicator(sens)) 66 | 67 | max_stack_frames_size = config[CONF_MAX_STACK_FRAMES_SIZE] 68 | cg.add_define("CRASH_INFO_MAX_STACK_FRAMES_SIZE", max_stack_frames_size) 69 | min_stack_frames_addr = config[CONF_MIN_STACK_FRAMES_ADDR] 70 | cg.add_define("CRASH_INFO_MIN_STACK_FRAMES_ADDR", min_stack_frames_addr) 71 | max_stack_frames_addr = config[CONF_MAX_STACK_FRAMES_ADDR] 72 | cg.add_define("CRASH_INFO_MAX_STACK_FRAMES_ADDR", max_stack_frames_addr) 73 | frames_in_line = config[CONF_FRAMES_IN_LINE] 74 | cg.add_define("CRASH_INFO_FRAMES_IN_LINE", frames_in_line) 75 | 76 | if config[CONF_STORE_IN_FLASH]: 77 | cg.add_define("CRASH_INFO_STORE_IN_FLASH") 78 | 79 | num_bytes = 1 + 1 + (config[CONF_MAX_STACK_FRAMES_SIZE] * 4) 80 | extended_with = [] 81 | 82 | if config[CONF_STORE_FREE_HEAP]: 83 | cg.add_define("CRASH_INFO_STORE_FREE_HEAP") 84 | num_bytes += 2 85 | extended_with.append("free_heap") 86 | 87 | if "time" in CORE.loaded_integrations: 88 | num_bytes += 8 89 | extended_with.append("time") 90 | 91 | if len(extended_with) > 0: 92 | extended_with = f" (extended with {', '.join(extended_with)})" 93 | else: 94 | extended_with = "" 95 | 96 | save_type = "FLASH" if config[CONF_STORE_IN_FLASH] else "RTC" 97 | _LOGGER.info( 98 | "Crash info will take %u bytes of %s memory%s", 99 | num_bytes, 100 | save_type, 101 | extended_with, 102 | ) 103 | -------------------------------------------------------------------------------- /esphome/custom_components/crash_info/crash_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/component.h" 4 | #include "esphome/core/preferences.h" 5 | #include "esphome/core/defines.h" 6 | #include "esphome/components/binary_sensor/binary_sensor.h" 7 | 8 | // maximum number of stack frames saved to RTC or FLASH. 9 | #ifndef CRASH_INFO_MAX_STACK_FRAMES_SIZE 10 | #define CRASH_INFO_MAX_STACK_FRAMES_SIZE 10 11 | #endif 12 | // minimum stack frame address. 13 | #ifndef CRASH_INFO_MIN_STACK_FRAMES_ADDR 14 | #define CRASH_INFO_MIN_STACK_FRAMES_ADDR 0x40000000 15 | #endif 16 | // maximum stack frame address. 17 | #ifndef CRASH_INFO_MAX_STACK_FRAMES_ADDR 18 | #define CRASH_INFO_MAX_STACK_FRAMES_ADDR 0x50000000 19 | #endif 20 | // number of frames to show in line 21 | #ifndef CRASH_INFO_FRAMES_IN_LINE 22 | #define CRASH_INFO_FRAMES_IN_LINE 4 23 | #endif 24 | 25 | namespace esphome { 26 | namespace crash_info { 27 | 28 | class CrashInfo : public Component { 29 | public: 30 | CrashInfo(); 31 | float get_setup_priority() const override { return setup_priority::LATE; } 32 | void setup() override; 33 | void dump_config() override; 34 | 35 | void set_indicator(binary_sensor::BinarySensor *indicator) { this->indicator_ = indicator; } 36 | 37 | void reset(); 38 | 39 | void save_crash_info(uint8_t reason, uint8_t exccause, const uint32_t *stack, size_t stack_size); 40 | 41 | uint32_t get_max_stack_frames_size() const { return CRASH_INFO_MAX_STACK_FRAMES_SIZE; } 42 | uint32_t get_min_stack_frames_addr() const { return CRASH_INFO_MIN_STACK_FRAMES_ADDR; } 43 | uint32_t get_max_stack_frames_addr() const { return CRASH_INFO_MAX_STACK_FRAMES_ADDR; } 44 | size_t get_frames_in_line() const { return CRASH_INFO_FRAMES_IN_LINE; } 45 | 46 | bool is_store_in_flash() const { 47 | #ifdef CRASH_INFO_STORE_IN_FLASH 48 | return true; 49 | #else 50 | return false; 51 | #endif 52 | } 53 | 54 | std::string get_stack_frames(); 55 | uint16_t get_free_heap(); 56 | 57 | protected: 58 | ESPPreferenceObject rtc_; 59 | binary_sensor::BinarySensor *indicator_{}; 60 | }; 61 | 62 | } // namespace crash_info 63 | } // namespace esphome 64 | -------------------------------------------------------------------------------- /esphome/custom_components/heapmon/README.md: -------------------------------------------------------------------------------- 1 | # heap space monitor 2 | 3 | A sensor to show the available heap space. 4 | 5 | Example: 6 | ```yaml 7 | sensor: 8 | - platform: heapmon 9 | id: heapspace 10 | name: "Free Space" 11 | ``` 12 | -------------------------------------------------------------------------------- /esphome/custom_components/heapmon/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/custom_components/heapmon/__init__.py -------------------------------------------------------------------------------- /esphome/custom_components/heapmon/heapmon.cpp: -------------------------------------------------------------------------------- 1 | #include "heapmon.h" 2 | #include "esphome/core/log.h" 3 | 4 | #ifdef USE_ESP_IDF 5 | #include 6 | #include 7 | #endif 8 | 9 | #ifdef USE_ARDUINO 10 | #include 11 | #endif 12 | 13 | namespace esphome { 14 | namespace debug { 15 | 16 | static const char *TAG = "heapmon"; 17 | 18 | void HeapMonitor::update() { 19 | uint32_t free_heap; 20 | #ifdef USE_ARDUINO 21 | free_heap = ESP.getFreeHeap(); 22 | #elif defined(USE_ESP_IDF) 23 | free_heap = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); 24 | #endif 25 | 26 | // ESP.getFreeHeap() - returns total amount of available memory 27 | // ESP.getHeapFragmentation() - returns an indication of how badly the heap is fragmented. The bigger, the worse - over 50 is very bad. 28 | // ESP.getMaxFreeBlockSize() - the biggest block you can allocate. 29 | 30 | ESP_LOGD(TAG, "Free Heap Size: %u bytes", free_heap); 31 | this->publish_state(free_heap); 32 | } 33 | 34 | } // namespace debug 35 | } // namespace esphome 36 | -------------------------------------------------------------------------------- /esphome/custom_components/heapmon/heapmon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/component.h" 4 | #include "esphome/components/sensor/sensor.h" 5 | 6 | namespace esphome { 7 | namespace debug { 8 | 9 | class HeapMonitor : public sensor::Sensor, public PollingComponent { 10 | public: 11 | void update() override; 12 | float get_setup_priority() const override { return setup_priority::LATE; }; 13 | }; 14 | 15 | } // namespace debug 16 | } // namespace esphome 17 | -------------------------------------------------------------------------------- /esphome/custom_components/heapmon/sensor.py: -------------------------------------------------------------------------------- 1 | import esphome.config_validation as cv 2 | import esphome.codegen as cg 3 | from esphome.components import sensor 4 | from esphome.const import CONF_ID, ICON_GAUGE 5 | 6 | UNIT_BYTE = "B" 7 | 8 | debug_ns = cg.esphome_ns.namespace('debug') 9 | HeapMonitor = debug_ns.class_('HeapMonitor', cg.PollingComponent) 10 | CONFIG_SCHEMA = sensor.sensor_schema( 11 | HeapMonitor, 12 | unit_of_measurement=UNIT_BYTE, 13 | icon=ICON_GAUGE, 14 | accuracy_decimals=0 15 | ).extend(cv.polling_component_schema('60s')) 16 | 17 | async def to_code(config): 18 | var = cg.new_Pvariable(config[CONF_ID]) 19 | await cg.register_component(var, config) 20 | await sensor.register_sensor(var, config) 21 | -------------------------------------------------------------------------------- /esphome/custom_components/influxdb/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *~ 3 | -------------------------------------------------------------------------------- /esphome/custom_components/influxdb/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Espen Skjelnes Johnsen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 19 | OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /esphome/custom_components/influxdb/README.md: -------------------------------------------------------------------------------- 1 | # InfluxDB custom component for ESPHome 2 | 3 | This custom component allows you to send sensor updates from ESPHome to an 4 | InfluxDB database with UDP. 5 | 6 | 7 | ## Installation 8 | 9 | Clone this repository into `custom_components/influxdb` from the directory 10 | where your ESPHome configuration is stored. 11 | 12 | ```bash 13 | git clone https://github.com/la7dja/esphome-influxdb custom_components/influxdb 14 | ``` 15 | 16 | ## Usage 17 | 18 | Add `influxdb` section to your ESPHome configuration file. 19 | 20 | ### Example configuration 21 | 22 | ```yaml 23 | influxdb: 24 | host: "influxdb-host" 25 | sensors: 26 | meter_id: 27 | ignore: True 28 | ams_temperature: 29 | measurement: 'temperature' 30 | tags: 31 | room: kitchen 32 | ``` 33 | 34 | ### Configuration variables 35 | 36 | * **host** (Required, string): Hostname or IP for the InfluxDB server 37 | * **port** (Optional, int): Port number the InfluxDB server is listening on. Defaults to 8089. 38 | * **max\_packet_size** (Optional, int): Max size of UDP packets. Defaults to 500. 39 | * **send_timeout** (Optional, time): Time to wait before sending UDP packets which have not been filled to max size. Defaults to 100ms. 40 | * **publish_all** (Optional, boolean): If true publish updates from all sensors unless explicit ignored in per sensor configuration. If false only publish updates from sensors explicit configured. Defaults to True. 41 | * **tags** (Optional, mapping): Mapping of tag keys and values. Defaults to 'node: '. 42 | * **sensors** (Optional, mapping): Per sensor configuration. Keys are sensor IDs. All types of sensors are included in this mapping, there is no distinquin bettwi float, binary and text sensors. 43 | 44 | #### Sensor configuration variables 45 | 46 | * **ignore** (Optional, boolean): Whether or not to include updates for this sensor. Defaults to True. 47 | * **measurement** (Optional, string): Name of measurements with update from this sensor. Defaults to the sanitized name of the sensor. 48 | * **tags** (Optional, mapping): Additional tags added for this sensor. 49 | -------------------------------------------------------------------------------- /esphome/custom_components/influxdb/__init__.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.const import CONF_ID, CONF_PORT 4 | from esphome.core import coroutine_with_priority 5 | from esphome.core import CORE 6 | 7 | influxdb_ns = cg.esphome_ns.namespace('influxdb') 8 | InfluxDBWriter = influxdb_ns.class_('InfluxDBWriter', cg.Component, cg.Controller) 9 | 10 | CONF_HOST= 'host' 11 | CONF_SEND_TIMEOUT= 'send_timeout' 12 | CONF_MAX_PACKET_SIZE= 'max_packet_size' 13 | CONF_TAGS = 'tags' 14 | CONF_PUBLISH_ALL = 'publish_all' 15 | CONF_SENSORS = 'sensors' 16 | CONF_IGNORE = 'ignore' 17 | CONF_MEASUREMENT = 'measurement' 18 | 19 | 20 | SENSOR_SCHEMA = cv.Schema({ 21 | cv.validate_id_name: 22 | cv.Schema({ 23 | cv.Optional(CONF_IGNORE, default=False): cv.boolean, 24 | cv.Optional(CONF_MEASUREMENT): cv.string, 25 | cv.Optional(CONF_TAGS, default={}): cv.Schema({ 26 | cv.string: cv.string 27 | }) 28 | }) 29 | }) 30 | 31 | CONFIG_SCHEMA = cv.Schema({ 32 | cv.GenerateID(): cv.declare_id(InfluxDBWriter), 33 | cv.Required(CONF_HOST): cv.domain, 34 | cv.Optional(CONF_PORT, default=8089): cv.port, 35 | cv.Optional(CONF_SEND_TIMEOUT, default='100ms'): cv.positive_time_period_milliseconds, 36 | cv.Optional(CONF_MAX_PACKET_SIZE, default=500): cv.positive_not_null_int, 37 | cv.Optional(CONF_PUBLISH_ALL, default=True): cv.boolean, 38 | cv.Optional(CONF_TAGS, default={'node': CORE.name}): cv.Schema({ 39 | cv.valid_name: cv.valid_name 40 | }), 41 | cv.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA, 42 | }).extend(cv.COMPONENT_SCHEMA) 43 | 44 | 45 | @coroutine_with_priority(40) 46 | def to_code(config): 47 | var = cg.new_Pvariable(config[CONF_ID]) 48 | yield cg.register_component(var, config) 49 | 50 | cg.add(var.set_host(config[CONF_HOST])) 51 | cg.add(var.set_port(config[CONF_PORT])) 52 | cg.add(var.set_max_packet_size(config[CONF_MAX_PACKET_SIZE])) 53 | cg.add(var.set_send_timeout(config[CONF_SEND_TIMEOUT])) 54 | cg.add(var.set_publish_all(config[CONF_PUBLISH_ALL])) 55 | cg.add(var.set_tags(''.join(',{}={}'.format(tag, value) for tag, value in config[CONF_TAGS].items()))) 56 | for sensor_id, sensor_config in config[CONF_SENSORS].items(): 57 | if sensor_config[CONF_IGNORE] == False: 58 | tags = ''.join(',{}={}'.format(tag, value) for tag, value in {**config[CONF_TAGS] , **sensor_config[CONF_TAGS]}.items()) 59 | if 'measurement' in sensor_config: 60 | measurement = f"\"{sensor_config[CONF_MEASUREMENT]}\"" 61 | else: 62 | measurement = f"{sensor_id}->get_object_id()" 63 | cg.add(var.add_setup_callback(cg.RawExpression(f"[]() -> Nameable* {{ {sensor_id}->add_on_state_callback([](float state) {{ {config[CONF_ID]}->on_sensor_update({sensor_id}, {measurement}, \"{tags}\", state); }}); return {sensor_id}; }}"))) 64 | else: 65 | cg.add(var.add_setup_callback(cg.RawExpression(f"[]() -> Nameable* {{ return {sensor_id}; }}"))) 66 | 67 | cg.add_define('USE_INFLUXDB') 68 | cg.add_global(influxdb_ns.using) 69 | -------------------------------------------------------------------------------- /esphome/custom_components/influxdb/influxdb_writer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "esphome/core/log.h" 4 | #include "esphome/core/application.h" 5 | #include "influxdb_writer.h" 6 | 7 | #ifdef USE_LOGGER 8 | #include "esphome/components/logger/logger.h" 9 | #endif 10 | 11 | namespace esphome { 12 | namespace influxdb { 13 | 14 | static const char *TAG = "influxdb"; 15 | 16 | void InfluxDBWriter::setup() { 17 | ESP_LOGCONFIG(TAG, "Setting up InfluxDB Writer..."); 18 | std::vector objs; 19 | for(auto fun: setup_callbacks) 20 | objs.push_back(fun()); 21 | 22 | if (publish_all) { 23 | #ifdef USE_BINARY_SENSOR 24 | for (auto *obj : App.get_binary_sensors()) { 25 | if (!obj->is_internal() && std::none_of(objs.begin(), objs.end(), [&obj](Nameable *o) {return o == obj;})) 26 | obj->add_on_state_callback([this, obj](bool state) { this->on_sensor_update(obj, obj->get_object_id(), tags, state); }); 27 | } 28 | #endif 29 | #ifdef USE_SENSOR 30 | for (auto *obj : App.get_sensors()) { 31 | if (!obj->is_internal() && std::none_of(objs.begin(), objs.end(), [&obj](Nameable *o) {return o == obj;})) 32 | obj->add_on_state_callback([this, obj](float state) { this->on_sensor_update(obj, obj->get_object_id(), tags, state); }); 33 | } 34 | #endif 35 | #ifdef USE_TEXT_SENSOR 36 | for (auto *obj : App.get_text_sensors()) { 37 | if (!obj->is_internal() && std::none_of(objs.begin(), objs.end(), [&obj](Nameable *o) {return o == obj;})) 38 | obj->add_on_state_callback([this, obj](std::string state) { this->on_sensor_update(obj, obj->get_object_id(), tags, state); }); 39 | } 40 | #endif 41 | } 42 | } 43 | 44 | void InfluxDBWriter::loop() { 45 | if (packet_size > 0 && millis() >= packet_timeout) { 46 | udp.endPacket(); 47 | packet_size = 0; 48 | } 49 | } 50 | 51 | void InfluxDBWriter::write(std::string measurement, std::string tags, const std::string value, bool is_string) 52 | { 53 | std::string line = measurement + tags + " value=" + (is_string ? ("\"" + value + "\"") : value); 54 | 55 | if (line.size() > max_packet_size) { 56 | ESP_LOGW(TAG, "Line too large to fit in UDP packet: %s", line.c_str()); 57 | return; 58 | } 59 | 60 | if (packet_size + line.size() + 1 > max_packet_size) { 61 | udp.endPacket(); 62 | packet_size = 0; 63 | } 64 | 65 | if (packet_size == 0) { 66 | packet_timeout = millis() + send_timeout; 67 | udp.beginPacket(host.c_str(), port); 68 | } else 69 | udp.write('\n'); 70 | 71 | udp.write(line.data(), line.size()); 72 | packet_size += line.size(); 73 | } 74 | 75 | void InfluxDBWriter::dump_config() { 76 | ESP_LOGCONFIG(TAG, "InfluxDB Writer:"); 77 | ESP_LOGCONFIG(TAG, " Address: %s:%u", host.c_str(), port); 78 | } 79 | 80 | #ifdef USE_BINARY_SENSOR 81 | void InfluxDBWriter::on_sensor_update(binary_sensor::BinarySensor *obj, std::string measurement, std::string tags, bool state) { 82 | write(measurement, tags, state ? "t" : "f", false); 83 | } 84 | #endif 85 | 86 | #ifdef USE_SENSOR 87 | void InfluxDBWriter::on_sensor_update(sensor::Sensor *obj, std::string measurement, std::string tags, float state) { 88 | write(measurement, tags, to_string(state), false); 89 | } 90 | #endif 91 | 92 | #ifdef USE_TEXT_SENSOR 93 | void InfluxDBWriter::on_sensor_update(text_sensor::TextSensor *obj, std::string measurement, std::string tags, std::string state) { 94 | write(measurement, tags, state, true); 95 | } 96 | #endif 97 | 98 | } // namespace api 99 | } // namespace esphome 100 | -------------------------------------------------------------------------------- /esphome/custom_components/influxdb/influxdb_writer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "esphome/core/component.h" 7 | #include "esphome/core/controller.h" 8 | #include "esphome/core/defines.h" 9 | #include "esphome/core/log.h" 10 | 11 | namespace esphome { 12 | namespace influxdb { 13 | 14 | // struct SensorConfig { 15 | // bool ignore; 16 | // std::string measurement; 17 | // std:vector> tags; 18 | // } 19 | 20 | class InfluxDBWriter : public Component { 21 | public: 22 | InfluxDBWriter() : packet_size(0) { }; 23 | void setup() override; 24 | void loop() override; 25 | void dump_config() override; 26 | #ifdef USE_BINARY_SENSOR 27 | void on_sensor_update(binary_sensor::BinarySensor *obj, std::string measurement, std::string tags, bool state); 28 | #endif 29 | #ifdef USE_SENSOR 30 | void on_sensor_update(sensor::Sensor *obj, std::string measurement, std::string tags, float state); 31 | #endif 32 | #ifdef USE_TEXT_SENSOR 33 | void on_sensor_update(text_sensor::TextSensor *obj, std::string measurement, std::string tags, std::string state); 34 | #endif 35 | 36 | void set_host(std::string host) { this->host = host; }; 37 | void set_port(uint16_t port) { this->port = port; }; 38 | void set_send_timeout(int timeout) { send_timeout = timeout; }; 39 | void set_max_packet_size(int size) { max_packet_size = size; }; 40 | void set_tags(std::string tags) { this->tags = tags; }; 41 | void set_publish_all(bool all) { publish_all = all; }; 42 | void add_setup_callback(std::function fun) { setup_callbacks.push_back(fun); }; 43 | 44 | protected: 45 | void write(std::string measurement, std::string tags, const std::string value, bool is_string); 46 | 47 | uint16_t port; 48 | std::string host; 49 | int max_packet_size; 50 | int send_timeout; 51 | std::string tags; 52 | bool publish_all; 53 | 54 | std::vector> setup_callbacks; 55 | 56 | WiFiUDP udp; 57 | int packet_size; 58 | int packet_timeout; 59 | }; 60 | 61 | } // namespace api 62 | } // namespace esphome 63 | -------------------------------------------------------------------------------- /esphome/custom_components/izar-wmbus/README.md: -------------------------------------------------------------------------------- 1 | # Izar water meter reader (ESP8266 and ESP32 -based) 2 | The idea behind the project is to read Izar water meter current consumption 3 | 4 | Implementation is naive, and hardcoded in many places. It was meant to be simple ;) 5 | 6 | ## Required components 7 | - NodeMCU (however any ESP8266-based device should work fine) 8 | - CC1101 module (ideally with an antena tuned to 868MHz *) 9 | 10 | _Note_: While CC1101 chip is versatile and may by configured programatically to use different frequency, some PCB components has to be selected for better performance. Therefore, please pay attention to get the right one.More info here: https://wiki.fhem.de/wiki/Selbstbau_CUL 11 | 12 | I was able to use CC1101 board tuned for 433MHz correctly, though ;) 13 | 14 | ## Usage 15 | 16 | ``` 17 | IzarWmbus reader; 18 | 19 | void setup() { 20 | //somewhere in the setup 21 | reader.init(0); 22 | } 23 | 24 | 25 | IzarResultData data; 26 | 27 | void loop() { 28 | FetchResult result = reader.fetchPacket(&data); 29 | if (result == FETCH_SUCCESSFUL) { 30 | // we have new package! 31 | } 32 | } 33 | 34 | ``` 35 | 36 | 37 | ## Wiring 38 | ### ESP8266 39 | ``` 40 | CC1101 -> NodeMCU 41 | ================== 42 | SCK -> D5 43 | MISO -> D6 44 | MOSI -> D7 45 | CSN -> D8 46 | VCC -> 3V 47 | GND -> GND 48 | ``` 49 | 50 | ### ESP32-CAM 51 | My main challenge with wiring ESP32-CAM was use of the default SPI connection by camera module, so I had to divert to other pin set 52 | ``` 53 | 54 | CC1101 -> ESP32(left side) 55 | ============================ 56 | 5V 57 | GND 58 | MISO -> GPIO12 59 | MOSI -> GPIO13 60 | CSN -> GPIO15 61 | SCK -> GPIO14 62 | GPIO2 63 | GPIO4 64 | 65 | 66 | (right side) 67 | VCC -> 3V3 68 | GDN -> GND 69 | ``` 70 | 71 | More details about wiring in library this tool is using for connecting with CC1101: https://github.com/LSatan/SmartRC-CC1101-Driver-Lib 72 | 73 | ### CC1101 868Mhz pinout 74 | (connectors on the left, ANT on the right) 75 | 76 | ``` 77 | VCC ----------------- 78 | GND | | 79 | MOSI | | 80 | SCK | CC1101 | GND 81 | MISO | | ANT 82 | GDO2 | | GND 83 | GDO0 | crystal | 84 | CSN |_______________- 85 | ``` 86 | 87 | ## Building and usage 88 | The library is based on PlatformIO and is build through PlatformIO's toolchain. 89 | 90 | ## Related materials: 91 | - Application note on using CC1101 with Wirless MBUS: https://www.ti.com/lit/an/swra234a/swra234a.pdf 92 | - CULFW source code: https://github.com/heliflieger/a-culfw/ 93 | - App filtering WMBUS packets from RTL: https://github.com/xaelsouth/rtl-wmbus 94 | - Almighty WMBUS meters decoders library: https://github.com/weetmuts/wmbusmeters 95 | -------------------------------------------------------------------------------- /esphome/custom_components/izar-wmbus/izar_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "izar_utils.h" 2 | 3 | #include 4 | 5 | #define CRC_POLYNOM 0x3D65 6 | 7 | 8 | const uint8_t decoder[] = { 9 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 10 | 0xFF,0xFF,0xFF,0x03,0xFF,0x01,0x02,0xFF, 11 | 0xFF,0xFF,0xFF,0x07,0xFF,0xFF,0x00,0xFF, 12 | 0xFF,0x05,0x06,0xFF,0x04,0xFF,0xFF,0xFF, 13 | 0xFF,0xFF,0xFF,0x0B,0xFF,0x09,0x0A,0xFF, 14 | 0xFF,0x0F,0xFF,0xFF,0x08,0xFF,0xFF,0xFF, 15 | 0xFF,0x0D,0x0E,0xFF,0x0C,0xFF,0xFF,0xFF, 16 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF 17 | }; 18 | 19 | uint32_t uintFromBytes(uint8_t* data) { 20 | uint32_t result = data[0] << 24; 21 | result += data[1] << 16; 22 | result += data[2] << 8; 23 | result += data[3]; 24 | return result; 25 | } 26 | 27 | uint32_t uintFromBytesLittleEndian(uint8_t* data) { 28 | uint32_t result = data[3] << 24; 29 | result += data[2] << 16; 30 | result += data[1] << 8; 31 | result += data[0]; 32 | return result; 33 | } 34 | 35 | uint16_t uint16FromBytes(uint8_t* data) { 36 | uint16_t result = data[0] << 8; 37 | result += data[1]; 38 | return result; 39 | } 40 | 41 | uint32_t hashShiftKey(uint32_t key) { 42 | for (uint8_t i = 0; i < 8; i++) { 43 | uint8_t bit = GET_BIT(key, 1) ^ GET_BIT(key, 2) ^ GET_BIT(key, 11) ^ 44 | GET_BIT(key, 31); 45 | key <<= 1; 46 | key |= bit; 47 | } 48 | return key; 49 | } 50 | 51 | uint8_t decode3of6Single(uint8_t* encoded, uint8_t* decoded) { 52 | uint8_t data[4]; 53 | 54 | data[0] = decoder[encoded[2] & 0x3F]; 55 | data[1] = decoder[((encoded[2] & 0xC0) >> 6) | ((encoded[1] & 0x0F) << 2)]; 56 | data[2] = decoder[((encoded[1] & 0xF0) >> 4) | ((encoded[0] & 0x03) << 4)]; 57 | data[3] = decoder[((encoded[0] & 0xFC) >> 2)]; 58 | 59 | for (uint8_t i = 0; i < 4; i++) { 60 | if (data[i] == 0xFF) { 61 | return -1; 62 | } 63 | } 64 | 65 | // - Shift the encoded values into a byte buffer - 66 | decoded[0] = (data[3] << 4) | (data[2]); 67 | decoded[1] = (data[1] << 4) | (data[0]); 68 | 69 | return 0; 70 | } 71 | 72 | uint8_t decrypt(uint8_t* encoded, uint8_t len, uint8_t* decoded) { 73 | if (len < 15) { 74 | return 0; 75 | } 76 | 77 | uint32_t key = 0xdfd109e8; 78 | key ^= uintFromBytes(encoded + 2); 79 | key ^= uintFromBytes(encoded + 6); 80 | key ^= uintFromBytes(encoded + 10); 81 | 82 | const uint8_t size = len - 15; 83 | for (uint8_t i = 0; i < size; i++) { 84 | key = hashShiftKey(key); 85 | decoded[i] = encoded[i + 15] ^ (key & 0xFF); 86 | } 87 | 88 | if (decoded[0] != 0x4B) { 89 | return 0; 90 | } 91 | 92 | return size; 93 | } 94 | 95 | uint16_t crc16(uint16_t crcVal, uint8_t dataByte) { 96 | for (int i = 0; i < 8; i++) { 97 | if (((crcVal & 0x8000) >> 8) ^ (dataByte & 0x80)) { 98 | crcVal = (crcVal << 1) ^ CRC_POLYNOM; 99 | } else { 100 | crcVal = (crcVal << 1); 101 | } 102 | 103 | dataByte <<= 1; 104 | } 105 | 106 | return crcVal; 107 | } -------------------------------------------------------------------------------- /esphome/custom_components/izar-wmbus/izar_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef IZAR_UTILS 2 | #define IZAR_UTILS 3 | 4 | #include 5 | 6 | #define GET_BIT(var, pos) ((var >> pos) & 0x01) 7 | 8 | uint32_t uintFromBytes(uint8_t* data); 9 | uint32_t uintFromBytesLittleEndian(uint8_t* data); 10 | uint16_t uint16FromBytes(uint8_t* data); 11 | uint8_t decrypt(uint8_t* encoded, uint8_t len, uint8_t* decoded); 12 | uint8_t decode3of6Single(uint8_t* encoded, uint8_t* decoded); 13 | uint16_t crc16(uint16_t crcVal, uint8_t dataByte); 14 | 15 | #endif 16 | 17 | -------------------------------------------------------------------------------- /esphome/custom_components/izar-wmbus/izar_wmbus.h: -------------------------------------------------------------------------------- 1 | #ifndef IZAR_WMBUS 2 | #define IZAR_WMBUS 3 | #include 4 | #include 5 | 6 | 7 | enum FetchResult { 8 | FETCH_SUCCESSFUL, 9 | FETCH_NO_DATA, 10 | FETCH_OTHER_METER, 11 | FETCH_3OF6_ERROR, 12 | FETCH_CRC_ERROR, 13 | FETCH_NON_SENSIBLE_DATA 14 | }; 15 | 16 | struct IzarResultData { 17 | uint32_t meterId; 18 | uint32_t waterUsage; 19 | }; 20 | 21 | class IzarWmbus { 22 | public: 23 | const long int SENSIBLE_RESULT_THRESHOLD = 300000; 24 | 25 | 26 | void init(uint32_t waterMeter); 27 | FetchResult fetchPacket(IzarResultData* data); 28 | void ensureRx(); 29 | private: 30 | uint32_t waterMeterId = 0; 31 | const bool print_telegrams = 1; 32 | const bool print_decoded = 1; 33 | std::map lastResults; 34 | 35 | uint8_t ReceiveData2(byte *rxBuffer); 36 | static int decode3outOf6(uint8_t* input, uint8_t inputLen, uint8_t* output, uint8_t& errors); 37 | bool checkCRCForSection(uint8_t* section, uint8_t sectionLen); 38 | bool checkCRC(uint8_t* packet, uint8_t len); 39 | bool isSensibleResult(IzarResultData* data); 40 | 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /esphome/custom_components/izar-wmbus/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "izar-wmbus-esp-lib", 3 | "description": "This library can be used to provide readouts from IZAR water meter through CC1101 module at ESP8266 and ESP32 platforms", 4 | "keywords": "", 5 | "authors": { 6 | "name": "MaciekN" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/maciekn/izar-wmbus-esp" 11 | }, 12 | "version": "1.0.0", 13 | "frameworks": [ 14 | "arduino" 15 | ], 16 | "platforms": [ 17 | "espressif32", 18 | "espressif8266" 19 | ], 20 | "dependencies": { 21 | "lsatan/SmartRC-CC1101-Driver-Lib": "^2.5.7", 22 | "SPI": "*" 23 | } 24 | } -------------------------------------------------------------------------------- /esphome/custom_components/izar-wmbus/wmbus_t_cc1101_config.h: -------------------------------------------------------------------------------- 1 | #ifndef WMBUS_T_CC1101_CONFIG 2 | #define WMBUS_T_CC1101_CONFIG 3 | 4 | 5 | #include 6 | 7 | 8 | const uint8_t WMBUS_T_CC1101_CONFIG_LEN = 47; 9 | 10 | 11 | //based on https://www.ti.com/lit/an/swra234a/swra234a.pdf 12 | const uint8_t WMBUS_T_CC1101_CONFIG_BYTES[] = { 13 | CC1101_IOCFG2,0x06, 14 | CC1101_IOCFG1,0x2E, 15 | CC1101_IOCFG0,0x00, 16 | CC1101_FIFOTHR,0x7, 17 | CC1101_SYNC1,0x54, 18 | CC1101_SYNC0,0x3D, 19 | CC1101_PKTLEN,0xFF, 20 | CC1101_PKTCTRL1,0x0,// original: 0x4, disable APPEND_STATUS 21 | CC1101_PKTCTRL0,0x0, 22 | CC1101_ADDR,0x0, 23 | CC1101_CHANNR,0x0, 24 | CC1101_FSCTRL1,0x8, 25 | CC1101_FSCTRL0,0x0, 26 | CC1101_FREQ2,0x21, 27 | CC1101_FREQ1,0x6B, 28 | CC1101_FREQ0,0xD0, 29 | CC1101_MDMCFG4,0x5C, 30 | CC1101_MDMCFG3,0x4, 31 | CC1101_MDMCFG2,0x5, 32 | CC1101_MDMCFG1,0x22, 33 | CC1101_MDMCFG0,0xF8, 34 | CC1101_DEVIATN, 0x44, 35 | CC1101_MCSM2,0x7, 36 | CC1101_MCSM1,0x00, 37 | CC1101_MCSM0,0x18, 38 | CC1101_FOCCFG,0x2E, 39 | CC1101_BSCFG,0xBF, 40 | CC1101_AGCCTRL2,0x43, 41 | CC1101_AGCCTRL1,0x9, 42 | CC1101_AGCCTRL0,0xB5, 43 | CC1101_WOREVT1,0x87, 44 | CC1101_WOREVT0,0x6B, 45 | CC1101_WORCTRL,0xFB, 46 | CC1101_FREND1,0xB6, 47 | CC1101_FREND0,0x10, 48 | CC1101_FSCAL3,0xEA, 49 | CC1101_FSCAL2,0x2A, 50 | CC1101_FSCAL1,0x0, 51 | CC1101_FSCAL0,0x1F, 52 | CC1101_RCCTRL1,0x41, 53 | CC1101_RCCTRL0,0x0, 54 | CC1101_FSTEST,0x59, 55 | CC1101_PTEST,0x7F, 56 | CC1101_AGCTEST,0x3F, 57 | CC1101_TEST2,0x81, 58 | CC1101_TEST1,0x35, 59 | CC1101_TEST0,0x9 60 | }; 61 | 62 | 63 | #endif -------------------------------------------------------------------------------- /esphome/custom_components/izar_meter.h: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "ArduinoJson.h" 3 | #include "esphome.h" 4 | #include "izar_wmbus.h" 5 | 6 | // id for the current watermeter 7 | int meterId = 0x43410778; 8 | 9 | int waterUsage_temp; 10 | int waterUsage; 11 | IzarWmbus reader; 12 | 13 | namespace MyTextData { 14 | TextSensor *my_text_sensor = new TextSensor(); 15 | } 16 | 17 | class MyTextSensor : public Component, public TextSensor { 18 | public: 19 | TextSensor *my_text_sensor = MyTextData::my_text_sensor; 20 | }; 21 | 22 | class MySensor : public Component, public Sensor { 23 | public: 24 | Sensor *my_sensor = new Sensor(); 25 | 26 | void setup() { 27 | // to display all meters in range 28 | reader.init(0); 29 | 30 | // uncomment the line after identifying your meter 31 | // reader.init(meterId); 32 | } 33 | 34 | IzarResultData data; 35 | 36 | void loop() { 37 | 38 | FetchResult result = reader.fetchPacket(&data); 39 | 40 | if (result == FETCH_SUCCESSFUL) { 41 | 42 | waterUsage_temp = data.waterUsage; 43 | 44 | if ((waterUsage_temp > 0) and (waterUsage_temp < 10000000)) { //data filter 45 | waterUsage = waterUsage_temp; 46 | ESP_LOGD("IZAR WATERMETER", "waterUsage: %d", waterUsage); 47 | } 48 | 49 | //Uncomment from reading all the meters in the range. Comment this line after identifying your meter ID. 50 | int meterId = data.meterId; 51 | 52 | char ID_text[32]; 53 | itoa(meterId, ID_text, 16); 54 | 55 | // publish the ID to the custom text sensor 56 | ESP_LOGD("IZAR WATERMETER", "watermeterid: [0x%08X]", meterId); 57 | MyTextData::my_text_sensor->publish_state(ID_text); 58 | 59 | // publish the liter to the custom sensor 60 | my_sensor->publish_state(waterUsage); 61 | 62 | 63 | } else { 64 | // wait for 300 ms 65 | delay(300); 66 | reader.ensureRx(); 67 | } 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /esphome/custom_components/ping/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/custom_components/ping/__init__.py -------------------------------------------------------------------------------- /esphome/custom_components/ping/ping.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Tomoyuki Sakurai 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "esphome/components/sensor/sensor.h" 20 | 21 | namespace esphome { 22 | namespace ping { 23 | class PingSensor : public sensor::Sensor, public PollingComponent { 24 | public: 25 | Sensor *packet_loss_sensor = new Sensor(); 26 | Sensor *latency_sensor = new Sensor(); 27 | 28 | /* the sensor must be started after connecting WiFi */ 29 | float get_setup_priority() const override { return esphome::setup_priority::AFTER_WIFI; } 30 | 31 | void set_n_packet(uint32_t n) { n_packet = n; } 32 | void set_target(const std::string address) { target = address; } 33 | void set_timeout(uint32_t timeout_ms) { timeout = timeout_ms; } 34 | 35 | int get_latest_latency() { return latest_latency; } 36 | float get_latest_loss() { return latest_loss; } 37 | 38 | void set_packet_loss_sensor(sensor::Sensor *packet_loss_sensor) { packet_loss_sensor_ = packet_loss_sensor; } 39 | void set_latency_sensor(sensor::Sensor *latency_sensor) { latency_sensor_ = latency_sensor; } 40 | 41 | private: 42 | protected: 43 | int latest_latency = -1; 44 | int timeout = 1000; 45 | int n_packet = 13; 46 | float latest_loss = -1; 47 | std::string target = "8.8.8.8"; 48 | sensor::Sensor *packet_loss_sensor_{nullptr}; 49 | sensor::Sensor *latency_sensor_{nullptr}; 50 | 51 | void set_latest_loss(float f) { latest_loss = f; } 52 | void set_latest_latency(int i) { latest_latency = i; } 53 | }; 54 | 55 | } // namespace ping 56 | } // namespace esphome 57 | -------------------------------------------------------------------------------- /esphome/custom_components/ping/ping_esp8266.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Tomoyuki Sakurai 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #ifdef ARDUINO_ARCH_ESP8266 20 | #include "AsyncPing.h" 21 | 22 | #include "esphome/components/sensor/sensor.h" 23 | 24 | #define EACH_RESULT true 25 | #define END false 26 | #define TAG "ping" 27 | 28 | namespace esphome { 29 | namespace ping { 30 | class PingSensorESP8266 : public PingSensor { 31 | public: 32 | void setup() override { 33 | ping.on(EACH_RESULT, [this](const AsyncPingResponse &response) { 34 | if (response.answer) { 35 | ESP_LOGI(TAG, "%d bytes from %s: icmp_seq=%d ttl=%d time=%d ms", response.size, target.c_str(), 36 | response.icmp_seq, response.ttl, response.time); 37 | 38 | this->incr_total_success_time(response.time); 39 | } else { 40 | ESP_LOGI(TAG, "no reply from %s", target.c_str()); 41 | } 42 | return false; 43 | }); 44 | 45 | /* at the end, set the result */ 46 | ping.on(END, [this](const AsyncPingResponse &response) { 47 | float loss = 0; 48 | int total_failed_count = response.total_sent - response.total_recv; 49 | if (response.total_sent != 0) { 50 | loss = (float) total_failed_count / response.total_sent; 51 | } 52 | 53 | int mean = 0; 54 | if (response.total_recv != 0) { 55 | mean = total_success_time / response.total_recv; 56 | } 57 | 58 | this->set_latest_loss(loss * 100); 59 | this->set_latest_latency(mean); 60 | 61 | ESP_LOGI(TAG, "packet loss: %0.1f %% latency: %d ms", loss * 100, mean); 62 | this->reset(); 63 | return true; 64 | }); 65 | ping.begin(target.c_str(), n_packet, timeout); 66 | } 67 | 68 | void update() override { 69 | float loss; 70 | int latency_ms; 71 | 72 | loss = this->get_latest_loss(); 73 | latency_ms = this->get_latest_latency(); 74 | 75 | if (loss >= 0 && this->packet_loss_sensor_ != nullptr) { 76 | packet_loss_sensor_->publish_state(loss); 77 | } 78 | if (latency_ms >= 0 && this->latency_sensor_ != nullptr) { 79 | latency_sensor_->publish_state((float) latency_ms / 1000); 80 | } 81 | ping.begin(target.c_str(), n_packet, timeout); 82 | } 83 | 84 | private: 85 | protected: 86 | int total_success_time; 87 | void reset() { total_success_time = 0; } 88 | void incr_total_success_time(int time) { total_success_time += time; } 89 | 90 | AsyncPing ping; 91 | }; 92 | 93 | } // namespace ping 94 | } // namespace esphome 95 | #endif 96 | -------------------------------------------------------------------------------- /esphome/custom_components/ping/sensor.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Tomoyuki Sakurai 2 | # 3 | # Permission to use, copy, modify, and distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | import esphome.codegen as cg 16 | import esphome.config_validation as cv 17 | from esphome.components import sensor 18 | from esphome.const import ( 19 | CONF_ID, 20 | CONF_IP_ADDRESS, 21 | CONF_NUM_ATTEMPTS, 22 | CONF_TIMEOUT, 23 | STATE_CLASS_MEASUREMENT, 24 | UNIT_PERCENT, 25 | UNIT_SECOND, 26 | ICON_EMPTY, 27 | DEVICE_CLASS_EMPTY, 28 | ) 29 | from esphome.core import CORE 30 | 31 | DEPENDENCIES = ["network"] 32 | 33 | ping_ns = cg.esphome_ns.namespace("ping") 34 | 35 | if CORE.is_esp8266: 36 | PingSensor = ping_ns.class_("PingSensorESP8266", sensor.Sensor, cg.PollingComponent) 37 | elif CORE.is_esp32: 38 | PingSensor = ping_ns.class_("PingSensorESP32", sensor.Sensor, cg.PollingComponent) 39 | else: 40 | raise NotImplementedError 41 | 42 | 43 | def validate_timeout(n): 44 | n = cv.positive_time_period_microseconds(n) 45 | if n.total_seconds > 8: 46 | raise cv.Invalid("Maximum timeout cannot be greater than 8 seconds") 47 | return n 48 | 49 | 50 | CONF_LOSS = "loss" 51 | CONF_LATENCY = "latency" 52 | 53 | CONFIG_SCHEMA = cv.Schema( 54 | { 55 | cv.GenerateID(): cv.declare_id(PingSensor), 56 | cv.Optional(CONF_IP_ADDRESS, default="8.8.8.8"): cv.string, 57 | cv.Optional(CONF_TIMEOUT, default="1sec"): cv.positive_time_period_milliseconds, 58 | cv.Optional(CONF_NUM_ATTEMPTS, default=13): cv.int_range(min=1, max=60), 59 | cv.Optional(CONF_LOSS): sensor.sensor_schema( 60 | UNIT_PERCENT, 61 | ICON_EMPTY, 62 | 0, 63 | DEVICE_CLASS_EMPTY, 64 | STATE_CLASS_MEASUREMENT, 65 | ), 66 | cv.Optional(CONF_LATENCY): sensor.sensor_schema( 67 | UNIT_SECOND, 68 | ICON_EMPTY, 69 | 0, 70 | DEVICE_CLASS_EMPTY, 71 | STATE_CLASS_MEASUREMENT, 72 | ), 73 | } 74 | ).extend(cv.polling_component_schema("60s")) 75 | 76 | 77 | async def to_code(config): 78 | var = cg.new_Pvariable(config[CONF_ID]) 79 | await cg.register_component(var, config) 80 | 81 | cg.add(var.set_target(config[CONF_IP_ADDRESS])) 82 | cg.add(var.set_timeout(config[CONF_TIMEOUT])) 83 | cg.add(var.set_n_packet(config[CONF_NUM_ATTEMPTS])) 84 | 85 | if CONF_LOSS in config: 86 | sens = await sensor.new_sensor(config[CONF_LOSS]) 87 | cg.add(var.set_packet_loss_sensor(sens)) 88 | if CONF_LATENCY in config: 89 | sens = await sensor.new_sensor(config[CONF_LATENCY]) 90 | cg.add(var.set_latency_sensor(sens)) 91 | -------------------------------------------------------------------------------- /esphome/custom_components/startup/README.md: -------------------------------------------------------------------------------- 1 | # Startup Sensor 2 | 3 | The startup sensor is mostly like the [Uptime Sensor](https://esphome.io/components/sensor/uptime.html) and allows you to track the time the ESP has stayed up, but uses `Home Assistant` device class `timestamp`, so HA calculates uptime for you automatically. 4 | 5 | ```yaml 6 | # Example configuration entry 7 | sensor: 8 | - platform: startup 9 | name: Startup 10 | ``` 11 | 12 | ## Configuration variables: 13 | * **update_interval** (*Optional*, [Time](https://esphome.io/guides/configuration-types.html#config-time)): The interval to check the sensor. Defaults to 60s. 14 | * **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Set the ID of this sensor for use in lambdas. 15 | * All other options from Sensor. 16 | -------------------------------------------------------------------------------- /esphome/custom_components/startup/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/custom_components/startup/__init__.py -------------------------------------------------------------------------------- /esphome/custom_components/startup/sensor.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.components import sensor, time 4 | from esphome.const import ( 5 | CONF_TIME_ID, 6 | DEVICE_CLASS_TIMESTAMP, 7 | ENTITY_CATEGORY_DIAGNOSTIC, 8 | UNIT_EMPTY, 9 | ) 10 | 11 | ICON_CLOCK_START = "mdi:clock-start" 12 | 13 | CODEOWNERS = ["@zdzichu6969"] 14 | 15 | DEPENDENCIES = ["time"] 16 | 17 | startup_ns = cg.esphome_ns.namespace("startup") 18 | StartupSensor = startup_ns.class_("StartupSensor", sensor.Sensor, cg.PollingComponent) 19 | 20 | CONFIG_SCHEMA = ( 21 | sensor.sensor_schema( 22 | StartupSensor, 23 | unit_of_measurement=UNIT_EMPTY, 24 | icon=ICON_CLOCK_START, 25 | accuracy_decimals=0, 26 | device_class=DEVICE_CLASS_TIMESTAMP, 27 | entity_category=ENTITY_CATEGORY_DIAGNOSTIC, 28 | ) 29 | .extend( 30 | { 31 | cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), 32 | } 33 | ) 34 | .extend(cv.polling_component_schema("60s")) 35 | ) 36 | 37 | 38 | async def to_code(config): 39 | """Code generation entry point""" 40 | var = await sensor.new_sensor(config) 41 | await cg.register_component(var, config) 42 | 43 | tm = await cg.get_variable(config[CONF_TIME_ID]) 44 | cg.add(var.set_time(tm)) 45 | -------------------------------------------------------------------------------- /esphome/custom_components/startup/startup.cpp: -------------------------------------------------------------------------------- 1 | #include "esphome/core/log.h" 2 | #include "esphome/core/helpers.h" 3 | #include "esphome/core/hal.h" 4 | 5 | #include "startup.h" 6 | 7 | namespace esphome { 8 | namespace startup { 9 | 10 | static const char *const TAG = "startup"; 11 | 12 | StartupSensor::StartupSensor() : start_(millis()){}; 13 | 14 | void StartupSensor::dump_config() { LOG_SENSOR("", "Startup Sensor", this); } 15 | 16 | void StartupSensor::update() { 17 | if (this->startup_ != 0) { 18 | this->publish_state((float) this->startup_); 19 | } 20 | } 21 | 22 | void StartupSensor::loop() { 23 | if (startup_ != 0) { 24 | return; 25 | } 26 | 27 | auto now = this->time_->now(); 28 | if (!now.is_valid()) { 29 | // time is not sync yet 30 | return; 31 | } 32 | 33 | this->startup_ = now.timestamp - (millis() - this->start_) / 1000; 34 | } 35 | 36 | } // namespace startup 37 | } // namespace esphome 38 | -------------------------------------------------------------------------------- /esphome/custom_components/startup/startup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/component.h" 4 | #include "esphome/components/sensor/sensor.h" 5 | #include "esphome/components/time/real_time_clock.h" 6 | 7 | namespace esphome { 8 | namespace startup { 9 | 10 | class StartupSensor : public sensor::Sensor, public PollingComponent { 11 | public: 12 | StartupSensor(); 13 | 14 | float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }; 15 | void dump_config() override; 16 | void loop() override; 17 | void update() override; 18 | 19 | std::string unique_id() override { return get_mac_address() + "-startup"; }; 20 | 21 | void set_time(time::RealTimeClock *time) { this->time_ = time; } 22 | 23 | protected: 24 | time::RealTimeClock *time_; 25 | time_t startup_{0}; 26 | unsigned long start_; 27 | }; 28 | 29 | } // namespace startup 30 | } // namespace esphome 31 | -------------------------------------------------------------------------------- /esphome/custom_components/syslog/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /esphome/custom_components/syslog/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2021, Samuel (TheStaticTurtle) 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /esphome/custom_components/syslog/README.md: -------------------------------------------------------------------------------- 1 | # esphome_syslog 2 | 3 | A simple syslog component for esphome. The component is designed to auto attach itself to the logger core module (like the MQTT component does with the `log_topic`) 4 | 5 | This component uses the https://github.com/arcao/Syslog library version 2.0 at its core 6 | 7 | ## How to 8 | 9 | ### Manually 10 | To install, locate your `esphome` folder, create a folder named `custom_components` got into it and execute  11 | ```shell 12 | git clone https://github.com/TheStaticTurtle/esphome_syslog.git 13 | mv esphome_syslog/components/syslog . 14 | rm -rf esphome_syslog 15 | ``` 16 | ### YAML 17 | ```yaml 18 | external_components: 19 | - source: github://TheStaticTurtle/esphome_syslog 20 | components: [syslog] 21 | ``` 22 | 23 | ### Configuration 24 | Simply add this to the configuration of your esphome node:  25 | ```yaml 26 | syslog: 27 | ``` 28 | 29 | When used like this, the component will simply **broadcast its log to everyone on the network** to change this behavior you can add the `ip_address` and `port` option like this: 30 | ```yaml 31 | syslog: 32 |     ip_address: "192.168.1.53" 33 |     port: 514 34 | ``` 35 | 36 | Default behavior strips the esphome color tags from the log (The `033[0;xxx` and the `#033[0m`) if you do not want this set the `strip_colors` option to `False`. 37 | 38 | Default behavior also sets `enable_logger` to `True` if you wish to disable sending logger messages and only use the `syslog.log` action you can do so by setting it to `False`: 39 | 40 | The action `syslog.log` has 3 settings: 41 | ```yaml 42 | then: 43 | - syslog.log: 44 | level: 7 45 | tag: "custom_action" 46 | payload: "My log message" 47 | ``` 48 | 49 | Due to the differences in log levels of syslog and esphome I had to translate them, here is a table: 50 | | Esphome level                  | Syslog level | 51 | |--------------------------------|--------------| 52 | | ESPHOME_LOG_LEVEL_NONE         | LOG_EMERG    | 53 | | ESPHOME_LOG_LEVEL_ERROR        | LOG_ERR      | 54 | | ESPHOME_LOG_LEVEL_WARN         | LOG_WARNING  | 55 | | ESPHOME_LOG_LEVEL_INFO         | LOG_INFO     | 56 | | ESPHOME_LOG_LEVEL_CONFIG       | LOG_NOTICE   | 57 | | ESPHOME_LOG_LEVEL_DEBUG        | LOG_DEBUG    | 58 | | ESPHOME_LOG_LEVEL_VERBOSE      | LOG_DEBUG    | 59 | | ESPHOME_LOG_LEVEL_VERY_VERBOSE | LOG_DEBUG    | 60 | 61 | This table is however open to discussion as it's my interpretation, if you want to change it you can do so in the `syslog_component.cpp` file and change the array at line 22 62 | 63 | ## Warning 64 | This component should not break anything and should work with everything however if it doesn't please open an issue. 65 | I have successfully tested this component with an esp8266 and an esp32. BUT The esp32 seems to have issue when there is a lot of thing to send very fast which you can see turing boot when it prints the config, see [my comment in issue #7](https://github.com/TheStaticTurtle/esphome_syslog/issues/7#issuecomment-1236194816) for more details . 66 | -------------------------------------------------------------------------------- /esphome/custom_components/syslog/__init__.py: -------------------------------------------------------------------------------- 1 | import esphome.config_validation as cv 2 | import esphome.codegen as cg 3 | from esphome import automation 4 | from esphome.const import CONF_ID, CONF_IP_ADDRESS, CONF_PORT, CONF_CLIENT_ID, CONF_LEVEL, CONF_PAYLOAD, CONF_TAG 5 | from esphome.components.logger import LOG_LEVELS, is_log_level 6 | 7 | CONF_STRIP_COLORS = "strip_colors" 8 | CONF_ENABLE_LOGGER_MESSAGES = "enable_logger" 9 | CONF_MIN_LEVEL = "min_level" 10 | 11 | DEPENDENCIES = ['logger','network'] 12 | 13 | debug_ns = cg.esphome_ns.namespace('debug') 14 | syslog_ns = cg.esphome_ns.namespace('syslog') 15 | 16 | SyslogComponent = syslog_ns.class_('SyslogComponent', cg.Component) 17 | SyslogLogAction = syslog_ns.class_('SyslogLogAction', automation.Action) 18 | 19 | CONFIG_SCHEMA = cv.Schema({ 20 | cv.GenerateID(): cv.declare_id(SyslogComponent), 21 | cv.Optional(CONF_IP_ADDRESS, default="255.255.255.255"): cv.string_strict, 22 | cv.Optional(CONF_PORT, default=514): cv.port, 23 | cv.Optional(CONF_ENABLE_LOGGER_MESSAGES, default=True): cv.boolean, 24 | cv.Optional(CONF_STRIP_COLORS, default=True): cv.boolean, 25 | cv.Optional(CONF_MIN_LEVEL, default="DEBUG"): is_log_level, 26 | }) 27 | 28 | SYSLOG_LOG_ACTION_SCHEMA = cv.Schema({ 29 | cv.GenerateID(): cv.use_id(SyslogComponent), 30 | cv.Required(CONF_LEVEL): cv.templatable(cv.int_range(min=0, max=7)), 31 | cv.Required(CONF_TAG): cv.templatable(cv.string), 32 | cv.Required(CONF_PAYLOAD): cv.templatable(cv.string), 33 | }) 34 | 35 | def to_code(config): 36 | cg.add_library('Syslog', '2.0.0') 37 | 38 | var = cg.new_Pvariable(config[CONF_ID]) 39 | yield cg.register_component(var, config) 40 | 41 | cg.add(var.set_enable_logger_messages(config[CONF_ENABLE_LOGGER_MESSAGES])) 42 | cg.add(var.set_strip_colors(config[CONF_STRIP_COLORS])) 43 | cg.add(var.set_server_ip(config[CONF_IP_ADDRESS])) 44 | cg.add(var.set_server_port(config[CONF_PORT])) 45 | cg.add(var.set_min_log_level(LOG_LEVELS[config[CONF_MIN_LEVEL]])) 46 | 47 | @automation.register_action('syslog.log', SyslogLogAction, SYSLOG_LOG_ACTION_SCHEMA) 48 | def syslog_log_action_to_code(config, action_id, template_arg, args): 49 | paren = yield cg.get_variable(config[CONF_ID]) 50 | var = cg.new_Pvariable(action_id, template_arg, paren) 51 | 52 | template_ = yield cg.templatable(config[CONF_LEVEL], args, cg.uint8) 53 | cg.add(var.set_level(template_)) 54 | template_ = yield cg.templatable(config[CONF_TAG], args, cg.std_string) 55 | cg.add(var.set_tag(template_)) 56 | template_ = yield cg.templatable(config[CONF_PAYLOAD], args, cg.std_string) 57 | cg.add(var.set_payload(template_)) 58 | 59 | yield var 60 | -------------------------------------------------------------------------------- /esphome/custom_components/syslog/syslog_component.cpp: -------------------------------------------------------------------------------- 1 | #include "syslog_component.h" 2 | 3 | #include "esphome/core/log.h" 4 | #include "esphome/core/application.h" 5 | 6 | #ifdef USE_LOGGER 7 | #include "esphome/components/logger/logger.h" 8 | #endif 9 | /* 10 | #include "esphome/core/helpers.h" 11 | #include "esphome/core/defines.h" 12 | #include "esphome/core/version.h" 13 | */ 14 | 15 | namespace esphome { 16 | namespace syslog { 17 | 18 | static const char *TAG = "syslog"; 19 | 20 | //https://github.com/arcao/Syslog/blob/master/src/Syslog.h#L37-44 21 | //https://github.com/esphome/esphome/blob/5c86f332b269fd3e4bffcbdf3359a021419effdd/esphome/core/log.h#L19-26 22 | static const uint8_t esphome_to_syslog_log_levels[] = {0, 3, 4, 6, 5, 7, 7, 7}; 23 | 24 | SyslogComponent::SyslogComponent() { 25 | this->settings_.client_id = App.get_name(); 26 | // Get the WifiUDP client here instead of getting it in setup() to make sure we always have a client when calling log() 27 | // Calling log() without the device connected should not be an issue since there is a wifi connected check and WifiUDP fails "silently" and doesn't generate an exception anyways 28 | this->udp_ = new WiFiUDP(); 29 | } 30 | 31 | void SyslogComponent::setup() { 32 | this->log(ESPHOME_LOG_LEVEL_INFO , "syslog", "Syslog started"); 33 | ESP_LOGI(TAG, "Started"); 34 | 35 | #ifdef USE_LOGGER 36 | if (logger::global_logger != nullptr) { 37 | logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) { 38 | if(!this->enable_logger || (level > this->settings_.min_log_level)) return; 39 | if(this->strip_colors) { //Strips the "033[0;xxx" at the beginning and the "#033[0m" at the end of log messages 40 | std::string org_msg(message); 41 | this->log(level, tag, org_msg.substr(7, org_msg.size() -7 -4)); 42 | } else { 43 | this->log(level, tag, message); 44 | } 45 | }); 46 | } 47 | #endif 48 | } 49 | 50 | void SyslogComponent::loop() { 51 | } 52 | 53 | void SyslogComponent::log(uint8_t level, const std::string &tag, const std::string &payload) { 54 | level = level > 7 ? 7 : level; 55 | 56 | // Simple check to make sure that there is connectivity, if not, log the issue and return 57 | if(WiFi.status() != WL_CONNECTED) { 58 | ESP_LOGW(TAG, "Tried to send \"%s\"@\"%s\" with level %d but Wifi isn't connected yet", tag.c_str(), payload.c_str(), level); 59 | return; 60 | } 61 | 62 | Syslog syslog( 63 | *this->udp_, 64 | this->settings_.address.c_str(), 65 | this->settings_.port, 66 | this->settings_.client_id.c_str(), 67 | tag.c_str(), 68 | LOG_KERN 69 | ); 70 | if(!syslog.log(esphome_to_syslog_log_levels[level], payload.c_str())) { 71 | ESP_LOGW(TAG, "Tried to send \"%s\"@\"%s\" with level %d but but failed for an unknown reason", tag.c_str(), payload.c_str(), level); 72 | } 73 | } 74 | 75 | float SyslogComponent::get_setup_priority() const { 76 | return setup_priority::AFTER_WIFI; 77 | } 78 | 79 | } // namespace syslog 80 | } // namespace esphome 81 | -------------------------------------------------------------------------------- /esphome/custom_components/syslog/syslog_component.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SYSLOG_COMPONENT_H_0504CB6C_15D8_4AB4_A04C_8AF9063B737F 3 | #define SYSLOG_COMPONENT_H_0504CB6C_15D8_4AB4_A04C_8AF9063B737F 4 | 5 | #include "esphome/core/component.h" 6 | #include "esphome/core/defines.h" 7 | #include "esphome/core/automation.h" 8 | #include "esphome/core/log.h" 9 | #include 10 | #include 11 | 12 | #if defined ESP8266 || defined ARDUINO_ESP8266_ESP01 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | #include 19 | 20 | namespace esphome { 21 | namespace syslog { 22 | 23 | struct SYSLOGSettings { 24 | std::string address; 25 | uint16_t port; 26 | std::string client_id; 27 | int min_log_level; 28 | }; 29 | 30 | //class UDP; 31 | 32 | class SyslogComponent : public Component { 33 | public: 34 | SyslogComponent(); 35 | 36 | float get_setup_priority() const override; 37 | 38 | void setup() override; 39 | void loop() override; 40 | 41 | void set_server_ip(const std::string &address) { this->settings_.address = address; } 42 | void set_server_port(uint16_t port) { this->settings_.port = port; } 43 | void set_client_id(const std::string &client_id) { this->settings_.client_id = client_id; } 44 | void set_min_log_level(int log_level) { this->settings_.min_log_level = log_level; } 45 | 46 | void set_enable_logger_messages(bool en) { this->enable_logger = en; } 47 | void set_strip_colors(bool strip_colors) { this->strip_colors = strip_colors; } 48 | 49 | void log(uint8_t level, const std::string &tag, const std::string &payload); 50 | protected: 51 | bool strip_colors; 52 | bool enable_logger; 53 | SYSLOGSettings settings_; 54 | UDP *udp_ = NULL; 55 | }; 56 | 57 | template class SyslogLogAction : public Action { 58 | public: 59 | SyslogLogAction(SyslogComponent *parent) : parent_(parent) {} 60 | TEMPLATABLE_VALUE(uint8_t, level) 61 | TEMPLATABLE_VALUE(std::string, tag) 62 | TEMPLATABLE_VALUE(std::string, payload) 63 | 64 | void play(Ts... x) override { 65 | this->parent_->log(this->level_.value(x...), this->tag_.value(x...), this->payload_.value(x...)); 66 | } 67 | 68 | protected: 69 | SyslogComponent *parent_; 70 | }; 71 | 72 | } // namespace syslog 73 | } // namespace esphome 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /esphome/custom_components/water_statistics/README.md: -------------------------------------------------------------------------------- 1 | # Water Statistics 2 | 3 | Gather statistics for: 4 | * today 5 | * yesterday 6 | * week 7 | * month 8 | 9 | ```yaml 10 | # Example configuration entry 11 | ... 12 | external_components: 13 | - source: 14 | type: local 15 | path: custom_components 16 | components: [water_statistics] 17 | refresh: 0s 18 | ... 19 | sensor: 20 | - platform: "water_statistics" 21 | total: total 22 | water_today: 23 | name: "$name Water Today" 24 | water_yesterday: 25 | name: "$name Water Yesterday" 26 | water_week: 27 | name: "$name Water Week" 28 | water_month: 29 | name: "$name Water Month" 30 | ``` 31 | 32 | ## Configuration variables: 33 | * **id** (*Optional*, [ID](https://esphome.io/guides/configuration-types.html#config-id)): Manually specify the ID used for code generation. 34 | * **total** (**Required**, [ID](https://esphome.io/guides/configuration-types.html#config-id)): The ID of the total power sensor. 35 | * **water_today** (*Optional*, Sensor): 36 | * Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor). 37 | * **water_yesterday** (*Optional*, Sensor): 38 | * Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor). 39 | * **water_week** (*Optional*, Sensor): 40 | * Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor). 41 | * **water_month** (*Optional*, Sensor): 42 | * Any options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor). 43 | -------------------------------------------------------------------------------- /esphome/custom_components/water_statistics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/custom_components/water_statistics/__init__.py -------------------------------------------------------------------------------- /esphome/custom_components/water_statistics/sensor.py: -------------------------------------------------------------------------------- 1 | import esphome.config_validation as cv 2 | import esphome.codegen as cg 3 | from esphome.components import sensor, time 4 | from esphome.const import ( 5 | CONF_ID, 6 | CONF_TIME_ID, 7 | CONF_POWER, 8 | CONF_TOTAL, 9 | DEVICE_CLASS_WATER, 10 | STATE_CLASS_TOTAL_INCREASING, 11 | UNIT_CUBIC_METER 12 | ) 13 | 14 | CODEOWNERS = ["@dentra"] 15 | 16 | DEPENDENCIES = ["time"] 17 | 18 | CONF_WATER_TODAY = "energy_today" 19 | CONF_WATER_YESTERDAY = "energy_yesterday" 20 | CONF_WATER_WEEK = "energy_week" 21 | CONF_WATER_MONTH = "energy_month" 22 | 23 | energy_statistics_ns = cg.esphome_ns.namespace("energy_statistics") 24 | 25 | EnergyStatistics = energy_statistics_ns.class_("EnergyStatistics", cg.Component) 26 | 27 | CONFIG_SCHEMA = cv.Schema( 28 | { 29 | cv.GenerateID(): cv.declare_id(EnergyStatistics), 30 | cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), 31 | cv.Required(CONF_TOTAL): cv.use_id(sensor.Sensor), 32 | cv.Optional(CONF_WATER_TODAY): sensor.sensor_schema( 33 | unit_of_measurement=UNIT_CUBIC_METER, 34 | accuracy_decimals=2, 35 | device_class=DEVICE_CLASS_WATER, 36 | state_class=STATE_CLASS_TOTAL_INCREASING, 37 | ), 38 | cv.Optional(CONF_WATER_YESTERDAY): sensor.sensor_schema( 39 | unit_of_measurement=UNIT_CUBIC_METER, 40 | accuracy_decimals=2, 41 | device_class=DEVICE_CLASS_WATER, 42 | state_class=STATE_CLASS_TOTAL_INCREASING, 43 | ), 44 | cv.Optional(CONF_WATER_WEEK): sensor.sensor_schema( 45 | unit_of_measurement=UNIT_CUBIC_METER, 46 | accuracy_decimals=2, 47 | device_class=DEVICE_CLASS_WATER, 48 | state_class=STATE_CLASS_TOTAL_INCREASING, 49 | ), 50 | cv.Optional(CONF_WATER_MONTH): sensor.sensor_schema( 51 | unit_of_measurement=UNIT_CUBIC_METER, 52 | accuracy_decimals=2, 53 | device_class=DEVICE_CLASS_WATER, 54 | state_class=STATE_CLASS_TOTAL_INCREASING, 55 | ), 56 | } 57 | ).extend(cv.COMPONENT_SCHEMA) 58 | 59 | 60 | async def setup_sensor(config, key, setter): 61 | """setting up sensor""" 62 | if key not in config: 63 | return None 64 | var = await sensor.new_sensor(config[key]) 65 | cg.add(setter(var)) 66 | return var 67 | 68 | 69 | async def setup_input(config, key, setter): 70 | """setting up input""" 71 | if key not in config: 72 | return None 73 | var = await cg.get_variable(config[key]) 74 | cg.add(setter(var)) 75 | return var 76 | 77 | 78 | # code generation entry point 79 | async def to_code(config): 80 | """Code generation entry point""" 81 | var = cg.new_Pvariable(config[CONF_ID]) 82 | await cg.register_component(var, config) 83 | 84 | await setup_input(config, CONF_TIME_ID, var.set_time) 85 | 86 | # input sensors 87 | await setup_input(config, CONF_POWER, var.set_power) 88 | await setup_input(config, CONF_TOTAL, var.set_total) 89 | 90 | # exposed sensors 91 | await setup_sensor(config, CONF_WATER_TODAY, var.set_WATER_today) 92 | await setup_sensor(config, CONF_WATER_YESTERDAY, var.set_WATER_yesterday) 93 | await setup_sensor(config, CONF_WATER_WEEK, var.set_WATER_week) 94 | await setup_sensor(config, CONF_WATER_MONTH, var.set_WATER_month) 95 | -------------------------------------------------------------------------------- /esphome/custom_components/water_statistics/water_statistics.cpp: -------------------------------------------------------------------------------- 1 | #include "esphome/core/log.h" 2 | #include "esphome/core/hal.h" 3 | #include "water_statistics.h" 4 | 5 | namespace esphome { 6 | namespace water_statistics { 7 | 8 | static const char *const TAG = "water_statistics"; 9 | static const char *const GAP = " "; 10 | 11 | void WaterStatistics::dump_config() { 12 | ESP_LOGCONFIG(TAG, "Water statistics sensors"); 13 | if (this->water_today_) { 14 | LOG_SENSOR(GAP, "Water Today", this->water_today_); 15 | } 16 | if (this->water_yesterday_) { 17 | LOG_SENSOR(GAP, "Water Yesterday", this->water_yesterday_); 18 | } 19 | if (this->water_week_) { 20 | LOG_SENSOR(GAP, "Water Week", this->water_week_); 21 | } 22 | if (this->water_month_) { 23 | LOG_SENSOR(GAP, "Water Month", this->water_month_); 24 | } 25 | } 26 | 27 | void WaterStatistics::setup() { 28 | this->total_->add_on_state_callback([this](float state) { this->process_(state); }); 29 | 30 | this->pref_ = global_preferences->make_preference(fnv1_hash(TAG)); 31 | 32 | water_data_t loaded{}; 33 | if (this->pref_.load(&loaded)) { 34 | this->water_ = loaded; 35 | auto total = this->total_->get_state(); 36 | if (!std::isnan(total)) { 37 | this->process_(total); 38 | } 39 | } 40 | } 41 | 42 | void WaterStatistics::loop() { 43 | const auto t = this->time_->now(); 44 | if (!t.is_valid()) { 45 | // time is not sync yet 46 | return; 47 | } 48 | 49 | const auto total = this->total_->get_state(); 50 | if (std::isnan(total)) { 51 | // total is not published yet 52 | return; 53 | } 54 | 55 | if (t.day_of_year == this->water_.current_day_of_year) { 56 | // nothing to do 57 | return; 58 | } 59 | 60 | this->water_.start_yesterday = this->water_.start_today; 61 | this->water_.start_today = total; 62 | 63 | if (this->water_.current_day_of_year != 0) { 64 | // at specified day of week we start a new week calculation 65 | if (t.day_of_week == this->water_week_start_day_) { 66 | this->water_.start_week = total; 67 | } 68 | // at first day of month we start a new month calculation 69 | if (t.day_of_month == 1) { 70 | this->water_.start_month = total; 71 | } 72 | } 73 | 74 | this->water_.current_day_of_year = t.day_of_year; 75 | 76 | this->process_(total); 77 | } 78 | 79 | void WaterStatistics::process_(float total) { 80 | if (this->water_today_ && !std::isnan(this->water_.start_today)) { 81 | this->water_today_->publish_state(total - this->water_.start_today); 82 | } 83 | 84 | if (this->water_yesterday_ && !std::isnan(this->water_.start_yesterday)) { 85 | this->water_yesterday_->publish_state(this->water_.start_today - this->water_.start_yesterday); 86 | } 87 | 88 | if (this->water_week_ && !std::isnan(this->water_.start_week)) { 89 | this->water_week_->publish_state(total - this->water_.start_week); 90 | } 91 | 92 | if (this->water_month_ && !std::isnan(this->water_.start_month)) { 93 | this->water_month_->publish_state(total - this->water_.start_month); 94 | } 95 | 96 | this->save_(); 97 | } 98 | 99 | void WaterStatistics::save_() { this->pref_.save(&(this->water_)); } 100 | 101 | } // namespace water_statistics 102 | } // namespace esphome 103 | -------------------------------------------------------------------------------- /esphome/custom_components/water_statistics/water_statistics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/component.h" 4 | #include "esphome/core/preferences.h" 5 | 6 | #include "esphome/components/sensor/sensor.h" 7 | #include "esphome/components/time/real_time_clock.h" 8 | 9 | namespace esphome { 10 | namespace water_statistics { 11 | 12 | using sensor::Sensor; 13 | 14 | class WaterStatistics : public Component { 15 | public: 16 | float get_setup_priority() const override { return setup_priority::DATA; } 17 | void dump_config() override; 18 | void setup() override; 19 | void loop() override; 20 | 21 | void set_time(time::RealTimeClock *time) { this->time_ = time; } 22 | void set_total(Sensor *sensor) { this->total_ = sensor; } 23 | 24 | void set_water_today(Sensor *sensor) { this->water_today_ = sensor; } 25 | void set_water_yesterday(Sensor *sensor) { this->water_yesterday_ = sensor; } 26 | void set_water_week(Sensor *sensor) { this->water_week_ = sensor; } 27 | void set_water_month(Sensor *sensor) { this->water_month_ = sensor; } 28 | 29 | protected: 30 | ESPPreferenceObject pref_; 31 | time::RealTimeClock *time_; 32 | 33 | // input sensors 34 | Sensor *total_{nullptr}; 35 | 36 | // exposed sensors 37 | Sensor *water_today_{nullptr}; 38 | Sensor *water_yesterday_{nullptr}; 39 | Sensor *water_week_{nullptr}; 40 | Sensor *water_month_{nullptr}; 41 | 42 | // start day of week configuration 43 | int water_week_start_day_{2}; 44 | // start day of month configuration 45 | int water_month_start_day_{1}; 46 | 47 | struct water_data_t { 48 | uint16_t current_day_of_year{0}; 49 | float start_today{NAN}; 50 | float start_yesterday{NAN}; 51 | float start_week{NAN}; 52 | float start_month{NAN}; 53 | } water_; 54 | 55 | void process_(float total); 56 | void save_(); 57 | }; // class waterStatistics 58 | 59 | } // namespace water_statistics 60 | } // namespace esphome 61 | -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/__init__.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome import pins 4 | from esphome.components import time 5 | from esphome.components.network import IPAddress 6 | from esphome.const import ( 7 | CONF_ID, 8 | CONF_MOSI_PIN, 9 | CONF_MISO_PIN, 10 | CONF_CLK_PIN, 11 | CONF_CS_PIN, 12 | CONF_NAME, 13 | CONF_IP_ADDRESS, 14 | CONF_PORT, 15 | CONF_FORMAT, 16 | CONF_TIME_ID, 17 | ) 18 | 19 | CONF_TRANSPORT = "transport" 20 | 21 | CONF_GDO0_PIN = "gdo0_pin" 22 | CONF_GDO2_PIN = "gdo2_pin" 23 | 24 | CONF_LED_PIN = "led_pin" 25 | CONF_LED_BLINK_TIME = "led_blink_time" 26 | 27 | CONF_LOG_UNKNOWN = "log_unknown" 28 | 29 | CONF_WMBUS_ID = "wmbus_id" 30 | 31 | CODEOWNERS = ["@SzczepanLeon"] 32 | 33 | DEPENDENCIES = ["time"] 34 | AUTO_LOAD = ["sensor"] 35 | 36 | wmbus_ns = cg.esphome_ns.namespace('wmbus') 37 | WMBusComponent = wmbus_ns.class_('WMBusComponent', cg.Component) 38 | Client = wmbus_ns.struct('Client') 39 | Format = wmbus_ns.enum("Format") 40 | Transport = wmbus_ns.enum("Transport") 41 | 42 | FORMAT = { 43 | "HEX": Format.FORMAT_HEX, 44 | "RTLWMBUS": Format.FORMAT_RTLWMBUS, 45 | } 46 | validate_format = cv.enum(FORMAT, upper=True) 47 | 48 | TRANSPORT = { 49 | "TCP": Transport.TRANSPORT_TCP, 50 | "UDP": Transport.TRANSPORT_UDP, 51 | } 52 | validate_transport = cv.enum(TRANSPORT, upper=True) 53 | 54 | CONF_CLIENTS = 'clients' 55 | 56 | CLIENT_SCHEMA = cv.Schema({ 57 | cv.GenerateID(): cv.declare_id(Client), 58 | cv.Required(CONF_NAME): cv.string_strict, 59 | cv.Required(CONF_IP_ADDRESS): cv.ipv4, 60 | cv.Required(CONF_PORT): cv.port, 61 | cv.Optional(CONF_TRANSPORT, default="TCP"): cv.templatable(validate_transport), 62 | cv.Optional(CONF_FORMAT, default="RTLWMBUS"): cv.templatable(validate_format), 63 | }) 64 | 65 | CONFIG_SCHEMA = cv.Schema({ 66 | cv.GenerateID(): cv.declare_id(WMBusComponent), 67 | cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), 68 | cv.Optional(CONF_MOSI_PIN, default=13): pins.internal_gpio_output_pin_schema, 69 | cv.Optional(CONF_MISO_PIN, default=12): pins.internal_gpio_input_pin_schema, 70 | cv.Optional(CONF_CLK_PIN, default=14): pins.internal_gpio_output_pin_schema, 71 | cv.Optional(CONF_CS_PIN, default=2): pins.internal_gpio_output_pin_schema, 72 | cv.Optional(CONF_GDO0_PIN, default=5): pins.internal_gpio_input_pin_schema, 73 | cv.Optional(CONF_GDO2_PIN, default=4): pins.internal_gpio_input_pin_schema, 74 | cv.Optional(CONF_LED_PIN): pins.gpio_output_pin_schema, 75 | cv.Optional(CONF_LED_BLINK_TIME, default="300ms"): cv.positive_time_period, 76 | cv.Optional(CONF_LOG_UNKNOWN, default=True): cv.boolean, 77 | cv.Optional(CONF_CLIENTS): cv.ensure_list(CLIENT_SCHEMA), 78 | }) 79 | 80 | def safe_ip(ip): 81 | if ip is None: 82 | return IPAddress(0, 0, 0, 0) 83 | return IPAddress(*ip.args) 84 | 85 | async def to_code(config): 86 | var = cg.new_Pvariable(config[CONF_ID]) 87 | await cg.register_component(var, config) 88 | 89 | mosi = await cg.gpio_pin_expression(config[CONF_MOSI_PIN]) 90 | miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN]) 91 | clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) 92 | cs = await cg.gpio_pin_expression(config[CONF_CS_PIN]) 93 | gdo0 = await cg.gpio_pin_expression(config[CONF_GDO0_PIN]) 94 | gdo2 = await cg.gpio_pin_expression(config[CONF_GDO2_PIN]) 95 | 96 | cg.add(var.add_cc1101(mosi, miso, clk, cs, gdo0, gdo2)) 97 | 98 | time = await cg.get_variable(config[CONF_TIME_ID]) 99 | cg.add(var.set_time(time)) 100 | 101 | if config[CONF_LOG_UNKNOWN]: 102 | cg.add(var.set_log_unknown()) 103 | 104 | for conf in config.get(CONF_CLIENTS, []): 105 | cg.add(var.add_client(conf[CONF_NAME], 106 | safe_ip(conf[CONF_IP_ADDRESS]), conf[CONF_PORT], conf[CONF_TRANSPORT], 107 | conf[CONF_FORMAT])) 108 | 109 | if CONF_LED_PIN in config: 110 | led_pin = await cg.gpio_pin_expression(config[CONF_LED_PIN]) 111 | cg.add(var.set_led_pin(led_pin)) 112 | cg.add(var.set_led_blink_time(config[CONF_LED_BLINK_TIME].total_milliseconds)) 113 | 114 | cg.add_library( 115 | None, 116 | None, 117 | "https://github.com/SzczepanLeon/wMbus-lib#1.1.1", 118 | ) 119 | -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_apator_08.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_apator08.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Apator08: Driver 14 | { 15 | Apator08() : Driver(std::string("apator08")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_total_water_m3(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | esphome::optional get_total_water_m3(std::vector &telegram) { 31 | esphome::optional ret_val{}; 32 | uint32_t usage = 0; 33 | // Seems that AT-WMBUS-08 is not decrypted. Maybe it is not true, but let's try ... 34 | size_t i = 11; 35 | usage = ((uint32_t)telegram[i+3] << 24) | ((uint32_t)telegram[i+2] << 16) | 36 | ((uint32_t)telegram[i+1] << 8) | ((uint32_t)telegram[i+0]); 37 | ret_val = (usage / 3.0) / 1000.0; 38 | return ret_val; 39 | }; 40 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_apatoreitn.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_apatoreitn.cc 3 | Copyright (C) 2019-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct ApatorEITN: Driver 14 | { 15 | ApatorEITN() : Driver(std::string("apatoreitn")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "current_hca", this->get_current_hca(telegram)); 20 | add_to_map(ret_val, "previous_hca", this->get_previous_hca(telegram)); 21 | add_to_map(ret_val, "temp_room_avg_c", this->get_temp_room_avg_c(telegram)); 22 | 23 | if (ret_val.size() > 0) { 24 | return ret_val; 25 | } 26 | else { 27 | return {}; 28 | } 29 | }; 30 | 31 | private: 32 | esphome::optional get_current_hca(std::vector &telegram) { 33 | esphome::optional ret_val{}; 34 | size_t i = 10; 35 | if (telegram[i] == 0xB6) { 36 | i += telegram[i+1] + 2; 37 | } 38 | 39 | ret_val = (((uint32_t)telegram[i+9] << 8) + (uint32_t)telegram[i+8]); 40 | 41 | return ret_val; 42 | }; 43 | 44 | esphome::optional get_previous_hca(std::vector &telegram) { 45 | esphome::optional ret_val{}; 46 | size_t i = 10; 47 | if (telegram[i] == 0xB6) { 48 | i += telegram[i+1] + 2; 49 | } 50 | 51 | ret_val = (((uint32_t)telegram[i+5] << 8) + (uint32_t)telegram[i+4]); 52 | 53 | return ret_val; 54 | }; 55 | 56 | esphome::optional get_temp_room_avg_c(std::vector &telegram) { 57 | esphome::optional ret_val{}; 58 | size_t i = 10; 59 | if (telegram[i] == 0xB6) { 60 | i += telegram[i+1] + 2; 61 | } 62 | 63 | ret_val = (((uint32_t)telegram[i+15]) + ((uint32_t)telegram[i+14])/256.0); 64 | 65 | return ret_val; 66 | }; 67 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_bmeters.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_hydrodigit.cc 3 | Copyright (C) 2019-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Bmeters: Driver 14 | { 15 | Bmeters() : Driver(std::string("bmeters")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0C13(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_c5isf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/wmbusmeters/wmbusmeters/blob/master/src/driver_c5isf.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct C5isf: Driver 14 | { 15 | C5isf() : Driver(std::string("c5isf")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_heating_kwh", this->get_0C0E(telegram)); 20 | add_to_map(ret_val, "total_heating_kwh", this->get_0C03(telegram)); 21 | 22 | if (ret_val.size() > 0) { 23 | return ret_val; 24 | } 25 | else { 26 | return {}; 27 | } 28 | }; 29 | 30 | private: 31 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_compact5.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_compact5.cc 3 | Copyright (C) 2019-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Compact5: Driver 14 | { 15 | Compact5() : Driver(std::string("compact5")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "current_heating_kwh", this->get_current_heating_kwh(telegram)); 20 | add_to_map(ret_val, "previous_heating_kwh", this->get_previous_heating_kwh(telegram)); 21 | 22 | if (ret_val.size() > 0) { 23 | return ret_val; 24 | } 25 | else { 26 | return {}; 27 | } 28 | }; 29 | 30 | private: 31 | esphome::optional get_current_heating_kwh(std::vector &telegram) { 32 | esphome::optional ret_val{}; 33 | size_t i = 11; 34 | 35 | ret_val = (((uint32_t)telegram[i+8] << 8) + (uint32_t)telegram[i+7]); 36 | 37 | return ret_val; 38 | }; 39 | 40 | esphome::optional get_previous_heating_kwh(std::vector &telegram) { 41 | esphome::optional ret_val{}; 42 | size_t i = 11; 43 | 44 | ret_val = (((uint32_t)telegram[i+4] << 8) + (uint32_t)telegram[i+3]); 45 | 46 | return ret_val; 47 | }; 48 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_elf.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_elf.cc 3 | Copyright (C) 2021-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Elf: Driver 14 | { 15 | Elf() : Driver(std::string("elf")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_energy_consumption_kwh", this->get_0E01(telegram)); 20 | add_to_map(ret_val, "total_energy_consumption_kwh", this->get_0E0A(telegram)); 21 | add_to_map(ret_val, "current_power_consumption_kw", this->get_0A2D(telegram)); 22 | add_to_map(ret_val, "total_water_m3", this->get_0C13(telegram)); 23 | 24 | if (ret_val.size() > 0) { 25 | return ret_val; 26 | } 27 | else { 28 | return {}; 29 | } 30 | }; 31 | 32 | private: 33 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_evo868.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_evo868.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Evo868: Driver 14 | { 15 | Evo868() : Driver(std::string("evo868")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0413(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_fhkvdataiii.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_fhkvdataiii.cc 3 | Copyright (C) 2019-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct FhkvdataIII: Driver 14 | { 15 | FhkvdataIII() : Driver(std::string("fhkvdataiii")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "current_hca", this->get_current_hca(telegram)); 20 | add_to_map(ret_val, "previous_hca", this->get_previous_hca(telegram)); 21 | 22 | if (ret_val.size() > 0) { 23 | return ret_val; 24 | } 25 | else { 26 | return {}; 27 | } 28 | }; 29 | 30 | private: 31 | esphome::optional get_current_hca(std::vector &telegram) { 32 | esphome::optional ret_val{}; 33 | size_t i = 11; 34 | 35 | ret_val = (((uint32_t)telegram[i+8] << 8) + (uint32_t)telegram[i+7]); 36 | 37 | return ret_val; 38 | }; 39 | 40 | esphome::optional get_previous_hca(std::vector &telegram) { 41 | esphome::optional ret_val{}; 42 | size_t i = 11; 43 | 44 | ret_val = (((uint32_t)telegram[i+4] << 8) + (uint32_t)telegram[i+3]); 45 | 46 | return ret_val; 47 | }; 48 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_hydrocalm3.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_hydrocalm3.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Hydrocalm3: Driver 14 | { 15 | Hydrocalm3() : Driver(std::string("hydrocalm3")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_heating_kwh", this->get_0C0E(telegram)); 20 | add_to_map(ret_val, "total_heating_kwh", this->get_0C03(telegram)); 21 | 22 | if (ret_val.size() > 0) { 23 | return ret_val; 24 | } 25 | else { 26 | return {}; 27 | } 28 | }; 29 | 30 | private: 31 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_hydrus.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/wmbusmeters/wmbusmeters/blob/master/src/driver_hydrus.cc 3 | Copyright (C) 2017-2023 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Hydrus: Driver 14 | { 15 | Hydrus() : Driver(std::string("hydrus")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0C13(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_iperl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/wmbusmeters/wmbusmeters/blob/master/src/driver_iperl.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Iperl: Driver 14 | { 15 | Iperl() : Driver(std::string("iperl")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0413(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_itron.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_itron.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Itron: Driver 14 | { 15 | Itron() : Driver(std::string("itron")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0C13(telegram)); 20 | add_to_map(ret_val, "total_water_m3", this->get_0413(telegram)); 21 | 22 | 23 | if (ret_val.size() > 0) { 24 | return ret_val; 25 | } 26 | else { 27 | return {}; 28 | } 29 | }; 30 | 31 | private: 32 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_mkradio3.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_mkradio3.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Mkradio3: Driver 14 | { 15 | Mkradio3() : Driver(std::string("mkradio3")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_total_water_m3(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | esphome::optional get_total_water_m3(std::vector &telegram) { 31 | esphome::optional ret_val{}; 32 | size_t i = 11; 33 | 34 | ret_val = ((((uint32_t)telegram[i+4] << 8) + (uint32_t)telegram[i+3]) / 10.0) + 35 | ((((uint32_t)telegram[i+8] << 8) + (uint32_t)telegram[i+7]) / 10.0); 36 | 37 | return ret_val; 38 | }; 39 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_mkradio4.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_mkradio4.cc 3 | Copyright (C) 2019-2023 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Mkradio4: Driver 14 | { 15 | Mkradio4() : Driver(std::string("mkradio4")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_total_water_m3(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | esphome::optional get_total_water_m3(std::vector &telegram) { 31 | esphome::optional ret_val{}; 32 | size_t i = 11; 33 | 34 | ret_val = ((((uint32_t)telegram[i+4] << 8) + (uint32_t)telegram[i+3]) / 10.0) + 35 | ((((uint32_t)telegram[i+8] << 8) + (uint32_t)telegram[i+7]) / 10.0); 36 | 37 | return ret_val; 38 | }; 39 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_qheat.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/wmbusmeters/wmbusmeters/blob/master/src/driver_qheat.cc 3 | Copyright (C) 2021-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Qheat: Driver 14 | { 15 | Qheat() : Driver(std::string("qheat")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_energy_consumption_kwh", this->get_0C0D(telegram)); 20 | add_to_map(ret_val, "total_energy_consumption_kwh", this->get_0C05(telegram)); 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_qwater.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/wmbusmeters/wmbusmeters/blob/master/src/driver_qwater.cc 3 | Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Qwater: Driver 14 | { 15 | Qwater() : Driver(std::string("qwater")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0C13(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_sharky774.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_sharky774.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Sharky774: Driver 14 | { 15 | Sharky774() : Driver(std::string("sharky774")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_energy_consumption_kwh", this->get_0C06(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_topaseskr.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/wmbusmeters/wmbusmeters/blob/master/src/driver_topaseskr.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct TopasESKR: Driver 14 | { 15 | TopasESKR() : Driver(std::string("topaseskr")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0C13(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_ultrimis.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_ultrimis.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Ultrimis: Driver 14 | { 15 | Ultrimis() : Driver(std::string("ultrimis")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_water_m3", this->get_0413(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_unismart.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_unismart.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Unismart: Driver 14 | { 15 | Unismart() : Driver(std::string("unismart")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_gas_m3", this->get_0C943A(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/driver_vario451.h: -------------------------------------------------------------------------------- 1 | /* 2 | Based on: https://github.com/weetmuts/wmbusmeters/blob/master/src/driver_vario451.cc 3 | Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later) 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "driver.h" 9 | 10 | #include 11 | #include 12 | 13 | struct Vario451: Driver 14 | { 15 | Vario451() : Driver(std::string("vario451")) {}; 16 | virtual esphome::optional> get_values(std::vector &telegram) override { 17 | std::map ret_val{}; 18 | 19 | add_to_map(ret_val, "total_heating_kwh", this->total_heating_kwh(telegram)); 20 | 21 | if (ret_val.size() > 0) { 22 | return ret_val; 23 | } 24 | else { 25 | return {}; 26 | } 27 | }; 28 | 29 | private: 30 | esphome::optional total_heating_kwh(std::vector &telegram) { 31 | esphome::optional ret_val{}; 32 | float usage = 0; 33 | size_t i = 11; 34 | 35 | usage = ((((uint32_t)telegram[i+4] << 8) + (uint32_t)telegram[i+3]) / 1000.0) + 36 | ((((uint32_t)telegram[i+8] << 8) + (uint32_t)telegram[i+7]) / 1000.0); 37 | // in kWh 38 | ret_val = usage * 277.777 ; 39 | 40 | return ret_val; 41 | }; 42 | }; -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/drivers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "driver_amiplus.h" 4 | #include "driver_apator_08.h" 5 | #include "driver_apator_16_2.h" 6 | #include "driver_apatoreitn.h" 7 | #include "driver_bmeters.h" 8 | #include "driver_c5isf.h" 9 | #include "driver_compact5.h" 10 | #include "driver_elf.h" 11 | #include "driver_evo868.h" 12 | #include "driver_fhkvdataiii.h" 13 | #include "driver_hydrocalm3.h" 14 | #include "driver_hydrus.h" 15 | #include "driver_iperl.h" 16 | #include "driver_itron.h" 17 | #include "driver_izar.h" 18 | #include "driver_mkradio3.h" 19 | #include "driver_mkradio4.h" 20 | #include "driver_qheat.h" 21 | #include "driver_qwater.h" 22 | #include "driver_sharky774.h" 23 | #include "driver_topaseskr.h" 24 | #include "driver_ultrimis.h" 25 | #include "driver_unismart.h" 26 | #include "driver_vario451.h" -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/version.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_VERSION 2 | #define MY_VERSION "2.1.13" 3 | #endif 4 | -------------------------------------------------------------------------------- /esphome/custom_components/wmbus/wmbus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/log.h" 4 | #include "esphome/core/gpio.h" 5 | #include "esphome/core/helpers.h" 6 | #include "esphome/core/component.h" 7 | #include "esphome/components/network/ip_address.h" 8 | #include "esphome/components/time/real_time_clock.h" 9 | #include "esphome/components/sensor/sensor.h" 10 | 11 | #include 12 | #include 13 | 14 | //wMBus lib 15 | #include "rf_mbus.hpp" 16 | #include "crc.hpp" 17 | #include "mbus_packet.hpp" 18 | #include "utils.hpp" 19 | 20 | #include "drivers.h" 21 | 22 | #include 23 | #include 24 | 25 | namespace esphome { 26 | namespace wmbus { 27 | 28 | enum Format : uint8_t { 29 | FORMAT_HEX = 0, 30 | FORMAT_RTLWMBUS = 1, 31 | }; 32 | 33 | enum Transport : uint8_t { 34 | TRANSPORT_TCP = 0, 35 | TRANSPORT_UDP = 1, 36 | }; 37 | 38 | struct Client { 39 | std::string name; 40 | network::IPAddress ip; 41 | uint16_t port; 42 | Transport transport; 43 | Format format; 44 | }; 45 | 46 | class WMBusListener { 47 | public: 48 | WMBusListener(const uint32_t id, const std::string type, const std::string key); 49 | uint32_t id; 50 | std::string type; 51 | std::vector key{}; 52 | std::map sensors_{}; 53 | void add_sensor(std::string type, sensor::Sensor *sensor) { 54 | this->sensors_[type] = sensor; 55 | }; 56 | 57 | void dump_config(); 58 | int char_to_int(char input); 59 | bool hex_to_bin(const std::string &src, std::vector *target) { return hex_to_bin(src.c_str(), target); }; 60 | bool hex_to_bin(const char* src, std::vector *target); 61 | }; 62 | 63 | struct Cc1101 { 64 | InternalGPIOPin *mosi{nullptr}; 65 | InternalGPIOPin *miso{nullptr}; 66 | InternalGPIOPin *clk{nullptr}; 67 | InternalGPIOPin *cs{nullptr}; 68 | InternalGPIOPin *gdo0{nullptr}; 69 | InternalGPIOPin *gdo2{nullptr}; 70 | }; 71 | 72 | class WMBusComponent : public Component { 73 | public: 74 | void setup() override; 75 | void loop() override; 76 | void dump_config() override; 77 | float get_setup_priority() const override { return setup_priority::LATE; } 78 | void set_led_pin(GPIOPin *led) { this->led_pin_ = led; } 79 | void set_led_blink_time(uint32_t led_blink_time) { this->led_blink_time_ = led_blink_time; } 80 | void register_wmbus_listener(WMBusListener *listener); 81 | void add_cc1101(InternalGPIOPin *mosi, InternalGPIOPin *miso, 82 | InternalGPIOPin *clk, InternalGPIOPin *cs, 83 | InternalGPIOPin *gdo0, InternalGPIOPin *gdo2) { 84 | this->spi_conf_.mosi = mosi; 85 | this->spi_conf_.miso = miso; 86 | this->spi_conf_.clk = clk; 87 | this->spi_conf_.cs = cs; 88 | this->spi_conf_.gdo0 = gdo0; 89 | this->spi_conf_.gdo2 = gdo2; 90 | } 91 | void set_time(time::RealTimeClock *time) { this->time_ = time; } 92 | void set_log_unknown() { this->log_unknown_ = true; } 93 | void add_client(const std::string name, 94 | const network::IPAddress ip, 95 | const uint16_t port, 96 | const Transport transport, 97 | const Format format) { 98 | clients_.push_back({name, ip, port, transport, format}); 99 | } 100 | 101 | private: 102 | 103 | protected: 104 | const LogString *format_to_string(Format format); 105 | const LogString *transport_to_string(Transport transport); 106 | void add_driver(Driver *driver); 107 | bool decrypt_telegram(std::vector &telegram, std::vector &key); 108 | void led_blink(); 109 | void led_handler(); 110 | HighFrequencyLoopRequester high_freq_; 111 | GPIOPin *led_pin_{nullptr}; 112 | Cc1101 spi_conf_{}; 113 | std::map wmbus_listeners_{}; 114 | std::map drivers_{}; 115 | std::vector clients_{}; 116 | WiFiClient tcp_client_; 117 | WiFiUDP udp_client_; 118 | time::RealTimeClock *time_{nullptr}; 119 | uint32_t led_blink_time_{0}; 120 | uint32_t led_on_millis_{0}; 121 | bool led_on_{false}; 122 | bool log_unknown_{false}; 123 | rf_mbus rf_mbus_; 124 | }; 125 | 126 | } // namespace wmbus 127 | } // namespace esphome -------------------------------------------------------------------------------- /esphome/custom_components/wmbusgw/__init__.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome import pins 4 | from esphome.components import time 5 | from esphome.components.network import IPAddress 6 | from esphome.const import ( 7 | CONF_ID, 8 | CONF_NAME, 9 | CONF_IP_ADDRESS, 10 | CONF_PORT, 11 | CONF_FORMAT, 12 | CONF_TIME_ID, 13 | CONF_REBOOT_TIMEOUT, 14 | CONF_MOSI_PIN, 15 | CONF_MISO_PIN, 16 | CONF_CLK_PIN, 17 | CONF_CS_PIN, 18 | ) 19 | 20 | CONF_GDO0_PIN = "gdo0_pin" 21 | CONF_GDO2_PIN = "gdo2_pin" 22 | 23 | CONF_TRANSPORT = "transport" 24 | 25 | DEPENDENCIES = ["time"] 26 | 27 | CODEOWNERS = ["@SzczepanLeon"] 28 | 29 | wmbusgw_ns = cg.esphome_ns.namespace('wmbusgw') 30 | WMBusGwComponent = wmbusgw_ns.class_('WMBusGwComponent', cg.Component) 31 | Client = wmbusgw_ns.struct('Client') 32 | Format = wmbusgw_ns.enum("Format") 33 | Transport = wmbusgw_ns.enum("Transport") 34 | Cc1101 = wmbusgw_ns.struct('Cc1101') 35 | 36 | FORMAT = { 37 | "HEX": Format.FORMAT_HEX, 38 | "RTLWMBUS": Format.FORMAT_RTLWMBUS, 39 | } 40 | validate_format = cv.enum(FORMAT, upper=True) 41 | 42 | TRANSPORT = { 43 | "TCP": Transport.TRANSPORT_TCP, 44 | "UDP": Transport.TRANSPORT_UDP, 45 | } 46 | validate_transport = cv.enum(TRANSPORT, upper=True) 47 | 48 | CONF_CLIENTS = 'clients' 49 | 50 | CLIENT_SCHEMA = cv.Schema({ 51 | cv.GenerateID(): cv.declare_id(Client), 52 | cv.Required(CONF_NAME): cv.string_strict, 53 | cv.Required(CONF_IP_ADDRESS): cv.ipv4, 54 | cv.Required(CONF_PORT): cv.port, 55 | cv.Optional(CONF_TRANSPORT, default="TCP"): cv.templatable(validate_transport), 56 | cv.Optional(CONF_FORMAT, default="HEX"): cv.templatable(validate_format), 57 | }) 58 | 59 | CONFIG_SCHEMA = cv.Schema({ 60 | cv.GenerateID(): cv.declare_id(WMBusGwComponent), 61 | cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock), 62 | cv.Required(CONF_MOSI_PIN): pins.internal_gpio_output_pin_schema, 63 | cv.Required(CONF_MISO_PIN): pins.internal_gpio_input_pin_schema, 64 | cv.Required(CONF_CLK_PIN): pins.internal_gpio_output_pin_schema, 65 | cv.Required(CONF_CS_PIN): pins.internal_gpio_output_pin_schema, 66 | cv.Required(CONF_GDO0_PIN): pins.internal_gpio_input_pin_schema, 67 | cv.Required(CONF_GDO2_PIN): pins.internal_gpio_input_pin_schema, 68 | cv.Optional(CONF_REBOOT_TIMEOUT, default="3min"): cv.positive_time_period_milliseconds, 69 | cv.Optional(CONF_CLIENTS): cv.ensure_list(CLIENT_SCHEMA), 70 | }) 71 | 72 | def safe_ip(ip): 73 | if ip is None: 74 | return IPAddress(0, 0, 0, 0) 75 | return IPAddress(*ip.args) 76 | 77 | def to_code(config): 78 | var = cg.new_Pvariable(config[CONF_ID]) 79 | yield cg.register_component(var, config) 80 | 81 | mosi = yield cg.gpio_pin_expression(config[CONF_MOSI_PIN]) 82 | miso = yield cg.gpio_pin_expression(config[CONF_MISO_PIN]) 83 | clk = yield cg.gpio_pin_expression(config[CONF_CLK_PIN]) 84 | cs = yield cg.gpio_pin_expression(config[CONF_CS_PIN]) 85 | gdo0 = yield cg.gpio_pin_expression(config[CONF_GDO0_PIN]) 86 | gdo2 = yield cg.gpio_pin_expression(config[CONF_GDO2_PIN]) 87 | 88 | cg.add(var.add_cc1101(mosi, miso, clk, cs, gdo0, gdo2)) 89 | cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) 90 | 91 | time_ = yield cg.get_variable(config[CONF_TIME_ID]) 92 | cg.add(var.set_time(time_)) 93 | 94 | for conf in config.get(CONF_CLIENTS, []): 95 | cg.add(var.add_client(conf[CONF_NAME], 96 | safe_ip(conf[CONF_IP_ADDRESS]), conf[CONF_PORT], conf[CONF_TRANSPORT], 97 | conf[CONF_FORMAT])) 98 | 99 | cg.add_library( 100 | None, 101 | None, 102 | "https://github.com/SzczepanLeon/wMbus-lib#0.9.15", 103 | ) 104 | -------------------------------------------------------------------------------- /esphome/custom_components/wmbusgw/wmbusgw_component.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome.h" 4 | #include "esphome/core/log.h" 5 | #include "esphome/core/component.h" 6 | #include "esphome/core/application.h" 7 | #include "esphome/components/network/ip_address.h" 8 | #include "esphome/components/time/real_time_clock.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | //wMBus lib 18 | #include "rf_mbus.hpp" 19 | #include "crc.hpp" 20 | #include "mbus_packet.hpp" 21 | #include "utils.hpp" 22 | 23 | namespace esphome { 24 | namespace wmbusgw { 25 | 26 | enum Format : uint8_t { 27 | FORMAT_HEX = 0, 28 | FORMAT_RTLWMBUS = 1, 29 | }; 30 | 31 | enum Transport : uint8_t { 32 | TRANSPORT_TCP = 0, 33 | TRANSPORT_UDP = 1, 34 | }; 35 | 36 | struct Client { 37 | std::string name; 38 | network::IPAddress ip; 39 | uint16_t port; 40 | Transport transport; 41 | Format format; 42 | }; 43 | 44 | struct Cc1101 { 45 | InternalGPIOPin *mosi{nullptr}; 46 | InternalGPIOPin *miso{nullptr}; 47 | InternalGPIOPin *clk{nullptr}; 48 | InternalGPIOPin *cs{nullptr}; 49 | InternalGPIOPin *gdo0{nullptr}; 50 | InternalGPIOPin *gdo2{nullptr}; 51 | }; 52 | 53 | class WMBusGwComponent : public esphome::Component { 54 | public: 55 | WMBusGwComponent(); 56 | ~WMBusGwComponent(); 57 | 58 | void setup() override; 59 | void loop() override; 60 | void dump_config() override; 61 | float get_setup_priority() const override { return setup_priority::LATE; } 62 | 63 | void set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; } 64 | void set_time(time::RealTimeClock *time) { this->time_ = time; } 65 | void add_client(const std::string name, 66 | const network::IPAddress ip, 67 | const uint16_t port, 68 | const Transport transport, 69 | const Format format) { 70 | if (transport == TRANSPORT_TCP) { 71 | this->only_udp_ = false; 72 | } 73 | clients_.push_back({name, ip, port, transport, format}); 74 | } 75 | 76 | void add_cc1101(InternalGPIOPin *mosi, InternalGPIOPin *miso, 77 | InternalGPIOPin *clk, InternalGPIOPin *cs, 78 | InternalGPIOPin *gdo0, InternalGPIOPin *gdo2) { 79 | this->spi_conf_.mosi = mosi; 80 | this->spi_conf_.miso = miso; 81 | this->spi_conf_.clk = clk; 82 | this->spi_conf_.cs = cs; 83 | this->spi_conf_.gdo0 = gdo0; 84 | this->spi_conf_.gdo2 = gdo2; 85 | } 86 | 87 | private: 88 | const LogString *format_to_string(Format format); 89 | const LogString *transport_to_string(Transport transport); 90 | 91 | protected: 92 | HighFrequencyLoopRequester high_freq_; 93 | uint32_t reboot_timeout_; 94 | std::vector clients_; 95 | Cc1101 spi_conf_; 96 | WiFiClient tcp_client_; 97 | WiFiUDP udp_client_; 98 | uint8_t mb_packet_[291]; 99 | time::RealTimeClock *time_; 100 | char telegram_time_[24]; 101 | uint32_t last_connected_{0}; 102 | bool only_udp_{true}; 103 | }; 104 | 105 | } // namespace wmbusgw 106 | } // namespace esphome 107 | -------------------------------------------------------------------------------- /esphome/docs/CC1101 SPI Adaptor_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/CC1101 SPI Adaptor_bottom.png -------------------------------------------------------------------------------- /esphome/docs/CC1101 SPI Adaptor_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/CC1101 SPI Adaptor_top.png -------------------------------------------------------------------------------- /esphome/docs/CC1101-868mhz-radio-module-pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/CC1101-868mhz-radio-module-pinout.jpg -------------------------------------------------------------------------------- /esphome/docs/CC1101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/CC1101.png -------------------------------------------------------------------------------- /esphome/docs/CC1101_Board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/CC1101_Board.png -------------------------------------------------------------------------------- /esphome/docs/D1MINI-ESP32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/D1MINI-ESP32.png -------------------------------------------------------------------------------- /esphome/docs/E07-900M10S-CC1101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/E07-900M10S-CC1101.png -------------------------------------------------------------------------------- /esphome/docs/E07-900M10S-CC1101_pins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/E07-900M10S-CC1101_pins.png -------------------------------------------------------------------------------- /esphome/docs/E07-900MBL-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/E07-900MBL-01.jpg -------------------------------------------------------------------------------- /esphome/docs/Ebyte E07-900MM10S.txt: -------------------------------------------------------------------------------- 1 | https://amzn.eu/d/bA0fmJE 2 | https://www.cdebyte.com/products/E07-900MM10S/2#Pin 3 | 4 | Ebyte E07-900MM10S Wireless Transmitter Module 10dBm Cheap Rf Module CC1101 1.5km 855-925MHz rf module 5 | E07-900MM10S uses Texas Instruments (TI) CC1101 chip as the core self-developed SMD wireless module. 6 | The working frequency range is 855-925 MHz, and it uses an industrial-grade high-precision 26MHz crystal 7 | oscillator. This series of modules is mainly aimed at smart home, industry, scientific research and 8 | medical and short-distance wireless communication equipment. Extensive hardware support for 9 | packet processing, data buffering, burst transfers, received signal strength indication (RSSI), 10 | clear channel assessment (CCA), link quality indication, and wake-on-wireless (WOR) is available. -------------------------------------------------------------------------------- /esphome/docs/IMAGE 2023-04-23 13:17:26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/IMAGE 2023-04-23 13:17:26.jpg -------------------------------------------------------------------------------- /esphome/docs/analog_vs_wmbus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/analog_vs_wmbus.jpg -------------------------------------------------------------------------------- /esphome/docs/az-delivery-devkit-v4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/az-delivery-devkit-v4.png -------------------------------------------------------------------------------- /esphome/docs/cc1101_board_pins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/cc1101_board_pins.png -------------------------------------------------------------------------------- /esphome/docs/cc1101_board_pins.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/cc1101_board_pins.pxm -------------------------------------------------------------------------------- /esphome/docs/cc1101_platine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/cc1101_platine.png -------------------------------------------------------------------------------- /esphome/docs/d1Mini-wemos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1Mini-wemos.png -------------------------------------------------------------------------------- /esphome/docs/d1Mini868Mhz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1Mini868Mhz.png -------------------------------------------------------------------------------- /esphome/docs/d1Mini_pinlayout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1Mini_pinlayout.png -------------------------------------------------------------------------------- /esphome/docs/d1mini-esp32-cc1101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1mini-esp32-cc1101.png -------------------------------------------------------------------------------- /esphome/docs/d1mini-esp8266MOD-12F.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1mini-esp8266MOD-12F.png -------------------------------------------------------------------------------- /esphome/docs/d1mini32_8266.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1mini32_8266.png -------------------------------------------------------------------------------- /esphome/docs/d1mini_CC1101.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1mini_CC1101.jpg -------------------------------------------------------------------------------- /esphome/docs/d1miniesp32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/d1miniesp32.png -------------------------------------------------------------------------------- /esphome/docs/eshome_webui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/eshome_webui.png -------------------------------------------------------------------------------- /esphome/docs/esp32-devkit_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esp32-devkit_v1.png -------------------------------------------------------------------------------- /esphome/docs/esp32-devkitv1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esp32-devkitv1.png -------------------------------------------------------------------------------- /esphome/docs/esp32_cc1101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esp32_cc1101.png -------------------------------------------------------------------------------- /esphome/docs/esp32_devkit_v1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esp32_devkit_v1.jpg -------------------------------------------------------------------------------- /esphome/docs/esp32_devkit_v1_cc1011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esp32_devkit_v1_cc1011.png -------------------------------------------------------------------------------- /esphome/docs/esphome-components-1.4.8.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esphome-components-1.4.8.zip -------------------------------------------------------------------------------- /esphome/docs/esphome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esphome.png -------------------------------------------------------------------------------- /esphome/docs/esphome_nodemcu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/esphome_nodemcu.png -------------------------------------------------------------------------------- /esphome/docs/ha-Device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha-Device.png -------------------------------------------------------------------------------- /esphome/docs/ha_rssi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha_rssi.png -------------------------------------------------------------------------------- /esphome/docs/ha_water-meter-esp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha_water-meter-esp.png -------------------------------------------------------------------------------- /esphome/docs/ha_water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha_water.png -------------------------------------------------------------------------------- /esphome/docs/ha_water_day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha_water_day.png -------------------------------------------------------------------------------- /esphome/docs/ha_water_year.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha_water_year.png -------------------------------------------------------------------------------- /esphome/docs/ha_waterdisplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha_waterdisplay.png -------------------------------------------------------------------------------- /esphome/docs/ha_wlan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/ha_wlan.png -------------------------------------------------------------------------------- /esphome/docs/homeassistant_service_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/homeassistant_service_call.png -------------------------------------------------------------------------------- /esphome/docs/homeassistat-water-meter-izar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/homeassistat-water-meter-izar.png -------------------------------------------------------------------------------- /esphome/docs/mdmini_v150.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/mdmini_v150.zip -------------------------------------------------------------------------------- /esphome/docs/memory_usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/memory_usage.png -------------------------------------------------------------------------------- /esphome/docs/nodemcu_cc1101.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/nodemcu_cc1101.jpg -------------------------------------------------------------------------------- /esphome/docs/nodemcu_v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/nodemcu_v3.png -------------------------------------------------------------------------------- /esphome/docs/postman_get_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/postman_get_config.png -------------------------------------------------------------------------------- /esphome/docs/schaltplan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/schaltplan.png -------------------------------------------------------------------------------- /esphome/docs/water-meter-d1mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/water-meter-d1mini.png -------------------------------------------------------------------------------- /esphome/docs/water-meter-esp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/water-meter-esp.png -------------------------------------------------------------------------------- /esphome/docs/water-meter-izar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/water-meter-izar.png -------------------------------------------------------------------------------- /esphome/docs/water-meter2-esp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/water-meter2-esp.png -------------------------------------------------------------------------------- /esphome/docs/watermeter-webserver3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/watermeter-webserver3.png -------------------------------------------------------------------------------- /esphome/docs/webserver_3_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/webserver_3_0.png -------------------------------------------------------------------------------- /esphome/docs/wlan_lgi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/docs/wlan_lgi.png -------------------------------------------------------------------------------- /esphome/template_secrets.yaml: -------------------------------------------------------------------------------- 1 | version: "3.0.0" 2 | 3 | # Your Wi-Fi's SSID and password 4 | # see: https://esphome.io/components/wifi 5 | wifi_ssid: 6 | wifi_password: 7 | 8 | ssid1_pswd: 9 | ssid1_name: 10 | 11 | ssid2_pswd: 12 | ssid2_name: 13 | 14 | ssid3_pswd: 15 | ssid3_name: 16 | 17 | ssid4_pswd: 18 | ssid4_name: 19 | 20 | # domain 21 | # Set the domain of the node hostname used for uploading. 22 | # For example, if it’s set to .local, all uploads will be sent to .local 23 | domain: .local 24 | 25 | # Passwords for appl, ota 26 | see: https://esphome.io/components/wifi 27 | app_pswd: 28 | # see: https://esphome.io/components/ota 29 | ota_pswd: 30 | hotspot_pswd: 31 | 32 | # UDP server wmbusmeter 33 | # see: https://github.com/SzczepanLeon/esphome-components#211-example-for-version-2x 34 | wmbus_server: 35 | wmbus_server_port: 7337 36 | 37 | # Backup 38 | # see: https://github.com/zdzichu6969/esphome-components 39 | web_username: 40 | web_password: 41 | 42 | # Watermeter ID, only HEX is working for me 43 | # meter_id (Required, int): Meter ID (usually from sticker). 44 | # Can be specified as decimal or hex. 45 | watermeterId: 0x43430778 46 | watermeterIx: 18444343 47 | 48 | # Using wmbusmeters i a pipe 49 | # see: https://github.com/wmbusmeters/wmbusmeters#using-wmbusmeters-in-a-pipe 50 | watermeterhost: 51 | wmbusmeter_host: 52 | 53 | # service host target (runUDPServer) 54 | # see: https://github.com/zibous/ha-watermeter/blob/master/tools/simpleserver.py 55 | service_host: 56 | data_host: 57 | 58 | # syslog, enable this if you have a syslog server 59 | # see: https://github.com/TheStaticTurtle/esphome_syslog 60 | syslog_server: 61 | syslog_port: 62 | 63 | # WEBSERVER settings 64 | # see: https://github.com/zibous/ha-watermeter/tree/master/esphome/webserver 65 | 66 | # webserver 3.0 change url to your webserver 67 | webserver_jsurl: "https://raw.githubusercontent.com/zibous/ha-watermeter/b0e3ed3f9b7c9f8da74bfe37389cee26ec8358e3/esphome/webserver/v3/www.js" 68 | webserver_cssurl: "https://raw.githubusercontent.com/zibous/ha-watermeter/b0e3ed3f9b7c9f8da74bfe37389cee26ec8358e3/esphome/webserver/v3/webserver.css" 69 | 70 | # webserver v2 change url to your webserver 71 | # if you have homeassistant installed, you can use it as webserver 72 | # copy the webserver to the homeassistant www folder and use: 73 | # http://homeassistant.local:8123/www/esphome/webserver/v3/www.js 74 | webserver2_jsurl: "http://homeassistant.local:8123/local/esphome/v2/www.js" 75 | 76 | # webserver v2 change url to your webserver 77 | # if you have homeassistant installed, you can use it as webserver 78 | # copy the webserver to the homeassistant www folder and use: 79 | # http://homeassistant.local:8123/www/esphome/webserver/v3/www.js 80 | webserver3_jsurl: "http://homeassistant.local:8123/local/esphome/v3/www.js" 81 | 82 | # webserver v1 change url to your webserver 83 | webserver1_jsurl: "https://espweb.local/esphome/v2/webserver-v1.js" 84 | webserver1_cssurl: "https://espweb.local/esphome/v1/webserver-v1.css" 85 | -------------------------------------------------------------------------------- /esphome/testcases/WLAN_ACCESS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/testcases/WLAN_ACCESS.png -------------------------------------------------------------------------------- /esphome/testcases/water-meter-dm32-test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/testcases/water-meter-dm32-test.bin -------------------------------------------------------------------------------- /esphome/testcases/water-meter-esp32-izar-test-dev.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/testcases/water-meter-esp32-izar-test-dev.bin -------------------------------------------------------------------------------- /esphome/testcases/water-meter-esp32-izar-test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/testcases/water-meter-esp32-izar-test.bin -------------------------------------------------------------------------------- /esphome/testcases/water-meter-esp32-izar-test2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/testcases/water-meter-esp32-izar-test2.bin -------------------------------------------------------------------------------- /esphome/testcases/water-meter-esp32-izar-test2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/testcases/water-meter-esp32-izar-test2.png -------------------------------------------------------------------------------- /esphome/testcases/water-meter-izar-test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/testcases/water-meter-izar-test.bin -------------------------------------------------------------------------------- /esphome/webserver/v1/webserver-v1.js: -------------------------------------------------------------------------------- 1 | const source = new EventSource("/events"); 2 | 3 | source.addEventListener('log', function (e) { 4 | const log = document.getElementById("log"); 5 | let log_prefs = [ 6 | ["\u001b[1;31m", 'e'], 7 | ["\u001b[0;33m", 'w'], 8 | ["\u001b[0;32m", 'i'], 9 | ["\u001b[0;35m", 'c'], 10 | ["\u001b[0;36m", 'd'], 11 | ["\u001b[0;37m", 'v'], 12 | ]; 13 | 14 | let klass = ''; 15 | for (const log_pref of log_prefs){ 16 | if (e.data.startsWith(log_pref[0])) { 17 | klass = log_pref[1]; 18 | } 19 | } 20 | if (klass == ''){ 21 | log.innerHTML += e.data + '\n'; 22 | } 23 | log.innerHTML += '' + e.data.substr(7, e.data.length - 11) + "\n"; 24 | }); 25 | 26 | actions = [ 27 | ["switch", ["toggle"]], 28 | ["light", ["toggle"]], 29 | ["fan", ["toggle"]], 30 | ["cover", ["open", "close"]], 31 | ["button", ["press"]], 32 | ["lock", ["lock", "unlock", "open"]], 33 | ]; 34 | multi_actions = [ 35 | ["select", "option"], 36 | ["number", "value"], 37 | ]; 38 | 39 | source.addEventListener('state', function (e) { 40 | const data = JSON.parse(e.data); 41 | document.getElementById(data.id).children[1].innerText = data.state; 42 | }); 43 | 44 | const states = document.getElementById("states"); 45 | let i = 0, row; 46 | for (; row = states.rows[i]; i++) { 47 | if (!row.children[2].children.length) { 48 | continue; 49 | } 50 | 51 | for (const domain of actions){ 52 | if (row.classList.contains(domain[0])) { 53 | let id = row.id.substr(domain[0].length+1); 54 | for (let j=0;j'+t.data.substr(7,t.data.length-11)+"\n"}),actions=[["switch",["toggle"]],["light",["toggle"]],["fan",["toggle"]],["cover",["open","close"]],["button",["press"]],["lock",["lock","unlock","open"]]],multi_actions=[["select","option"],["number","value"]],source.addEventListener("state",function(t){const e=JSON.parse(t.data);document.getElementById(e.id).children[1].innerText=e.state});const states=document.getElementById("states");let row,i=0;for(;row=states.rows[i];i++)if(row.children[2].children.length){for(const t of actions)if(row.classList.contains(t[0])){let e=row.id.substr(t[0].length+1);for(let n=0;n -------------------------------------------------------------------------------- /esphome/webserver/v2/index.html.br: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v2/index.html.br -------------------------------------------------------------------------------- /esphome/webserver/v2/index.html.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v2/index.html.gz -------------------------------------------------------------------------------- /esphome/webserver/v2/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /esphome/webserver/v2/www.js.br: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v2/www.js.br -------------------------------------------------------------------------------- /esphome/webserver/v2/www.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v2/www.js.gz -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-Black.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-Italic.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/fonts/Roboto/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/fonts/Roboto/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /esphome/webserver/v3/webserver.css: -------------------------------------------------------------------------------- 1 | /* Roboto regular */ 2 | @font-face { 3 | font-family: 'Roboto'; 4 | src: url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); 5 | font-weight: 400; 6 | font-style: normal; 7 | } 8 | /* Roboto Light */ 9 | @font-face { 10 | font-family: 'Roboto'; 11 | src: url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); 12 | font-weight: 400; 13 | font-style: normal; 14 | } 15 | 16 | /* Roboto bold */ 17 | @font-face { 18 | font-family: 'Roboto'; 19 | src: url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); 20 | font-weight: 700; 21 | font-style: normal; 22 | } 23 | 24 | body { 25 | margin: 0; 26 | padding: 0; 27 | max-height: 100%; 28 | background-color: #4b6cb7; 29 | font-family: 'Roboto', sans-serif; 30 | font-size: 18px; 31 | } 32 | 33 | @media (max-width: 920px) { 34 | body { 35 | font-size: 15px; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /esphome/webserver/v3/www.js.br: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/www.js.br -------------------------------------------------------------------------------- /esphome/webserver/v3/www.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/esphome/webserver/v3/www.js.gz -------------------------------------------------------------------------------- /ha-watermeter.md: -------------------------------------------------------------------------------- 1 | # ha-watermeter 2 | 3 | A simple Linux python script to query arbitrary smartmeter water sensor devices and send the data to an MQTT broker, e.g., the famous Eclipse Mosquitto. After data made the hop to the MQTT broker it can be used by home automation software, like openHAB or Home Assistant. 4 | 5 | ## Installation ha-watermeter Version 1.0.1 6 | 7 | On a modern Linux system just a few steps are needed to get the daemon working. The following example shows the installation under Debian/Raspbian below the `/opt` directory: 8 | 9 | ```bash 10 | $ git clone https://github.com/zibous/ha-watermeter.git /opt/ha-watermeter 11 | $ cd /opt/ha-watermeter 12 | $ sudo pip3 install -r requirements.txt 13 | 14 | ``` 15 | 16 | To match personal needs, all operation details can be configured using the file **config.py** The file needs to be created first: 17 | 18 | ```bash 19 | $ cd /opt/ha-watermeter 20 | $ cp config.py.dist config.py 21 | $ nano config.py 22 | 23 | $ chmod +x app.py 24 | $ python3 app.py ## or ./app.py 25 | ``` 26 | 27 | ### Application log 28 | 29 | ![logging](docs/logging.png) 30 | 31 | 32 | 33 | ### Continuous Daemon/Service 34 | 35 | You most probably want to execute the program **continuously in the background**. This can be done either by using the internal daemon or cron. 36 | 37 | **Attention:** Daemon mode must be enabled in the configuration file (default). 38 | 39 | 1. Systemd service - on systemd powered systems the **recommended** option 40 | 41 | ```bash 42 | sudo cp /opt/ha-watermeter/service.template /etc/systemd/system/ha-watermeter.service 43 | 44 | sudo systemctl daemon-reload 45 | sudo systemctl start ha-watermeter.service 46 | sudo systemctl status ha-watermeter.service 47 | 48 | sudo systemctl enable ha-watermeter.service 49 | ``` 50 | 51 | 52 | 53 | ## Results Homeassistant Card 54 | 55 | ![ha-card](docs/ha-card.png) 56 | 57 | 58 | Sensor setting see: [smartmeter-watermeter.yaml](docs/homeassistant) 59 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | if __name__ == '__main__' and __package__ is None: 3 | from os import sys, path 4 | PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__))) 5 | sys.path.append(PARENT_DIR) 6 | 7 | import lib.logger as logger 8 | import lib.calculator as calc 9 | name = 'lib' 10 | -------------------------------------------------------------------------------- /lib/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | import logging 4 | import sys 5 | import traceback 6 | from time import gmtime, strftime 7 | from config import * 8 | 9 | 10 | class CustomFormatter(logging.Formatter): 11 | """Logging colored formatter, adapted from https://stackoverflow.com/a/56944256/3638629""" 12 | 13 | grey = '\x1b[38;21m' 14 | blue = '\x1b[38;5;39m' 15 | yellow = '\x1b[38;5;226m' 16 | red = '\x1b[38;5;196m' 17 | bold_red = '\x1b[31;1m' 18 | reset = '\x1b[0m' 19 | 20 | def __init__(self, fmt): 21 | super().__init__() 22 | self.fmt = fmt 23 | self.FORMATS = { 24 | logging.DEBUG: self.grey + self.fmt + self.reset, 25 | logging.INFO: self.blue + self.fmt + self.reset, 26 | logging.WARNING: self.yellow + self.fmt + self.reset, 27 | logging.ERROR: self.red + self.fmt + self.reset, 28 | logging.CRITICAL: self.bold_red + self.fmt + self.reset 29 | } 30 | 31 | def format(self, record): 32 | log_fmt = self.FORMATS.get(record.levelno) 33 | date_fmt = "%Y/%m/%d %H:%M:%S" 34 | formatter = logging.Formatter(log_fmt,date_fmt) 35 | formatter.default_msec_format = '%s.%03d' 36 | return formatter.format(record) 37 | 38 | class Log(object): 39 | """Logging wrapper for better output 40 | """ 41 | 42 | def __init__(self, name: str='applogger', level: int = logging.DEBUG, logDir: str = None): 43 | """Constructor application logger 44 | 45 | Args: 46 | name (str, optional): [description]. Defaults to 'applogger'. 47 | level (int, optional): [description]. Defaults to logging.DEBUG. 48 | enableLogFile (bool, optional): [description]. Defaults to False 49 | """ 50 | self.logger = logging.getLogger(name) 51 | self.logger.setLevel(level) 52 | self.loglevel = level 53 | self.logDir = logDir 54 | 55 | if(logDir): 56 | # use log file 57 | fh = logging.FileHandler(self.logDir + '%s.log' % name, 'w') 58 | self.logger.addHandler(fh) 59 | 60 | fmt = "%(asctime)s.%(msecs)03d - %(levelname)s: %(message)s (%(name)s: Line %(lineno)d)" 61 | 62 | sh = logging.StreamHandler() 63 | sh.setFormatter(CustomFormatter(fmt)) 64 | self.logger.addHandler(sh) 65 | 66 | sys.excepthook = self.handle_excepthook 67 | 68 | def debug(self, msg): 69 | self.logger.debug(msg) 70 | 71 | def info(self, msg): 72 | self.logger.info(msg) 73 | 74 | def warning(self, msg): 75 | self.logger.warning(msg) 76 | 77 | def error(self, msg): 78 | self.logger.error(msg) 79 | 80 | def critical(self, msg): 81 | self.logger.critical(msg) 82 | 83 | def print(self, msg: str = ' ', end: str = '\r'): 84 | if(self.loglevel < 100): 85 | print(msg, end) 86 | 87 | def handle_excepthook_debug(self, type, message, stack): 88 | self.logger.critical(f'An unhandled exception occured: {message}. Traceback: {traceback.format_tb(stack)}') 89 | 90 | def handle_excepthook(self, type, message, stack): 91 | self.logger.error(f'An unhandled exception occured: {message}. Traceback: {traceback.extract_tb(stack,1)}') 92 | 93 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/logs/.gitkeep -------------------------------------------------------------------------------- /logs/data.csv: -------------------------------------------------------------------------------- 1 | watermeter,43430778,2020-07-15,13:36:54,2020-07-15T13:36:54Z,166.426,162.614,117.73,no_alarm,No alarm 2 | watermeter,43430778,2020-07-15,14:38:01,2020-07-15T14:38:01Z,166.428,162.614,117.73,no_alarm,No alarm 3 | watermeter,43430778,2020-07-16,08:57:41,2020-07-16T08:57:41Z,166.589,162.614,117.73,no_alarm,No alarm 4 | watermeter,43430778,2020-07-16,09:59:57,2020-07-16T09:59:57Z,166.606,162.614,117.73,no_alarm,no_alarm 5 | watermeter,43430778,2020-07-16,10:27:13,2020-07-16T10:27:13Z,166.611,162.614,117.73,no_alarm,No alarm 6 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 7 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 8 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 9 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 10 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 11 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 12 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 13 | watermeter,43430778,2020-07-16,13:45:18,2020-07-16T13:45:18Z,166.642,162.614,117.73,no_alarm,No alarm 14 | watermeter,43430778,2020-07-17,09:52:39,2020-07-17T09:52:39Z,166.814,162.614,117.73,no_alarm,No alarm 15 | watermeter,43430778,2020-07-17,12:58:44,2020-07-17T12:58:44Z,166.87,162.614,117.73,no_alarm,No alarm 16 | watermeter,43430778,2020-07-17,13:59:52,2020-07-17T13:59:52Z,166.899,162.614,117.73,no_alarm,no_alarm 17 | watermeter,43430778,2020-07-17,14:01:52,2020-07-17T14:01:52Z,166.899,162.614,117.73,no_alarm,No alarm 18 | watermeter,43430778,2022-02-11,08:22:10,2022-02-11T08:22:10Z,343.913,341.179,117.73,no_alarm,No alarm 19 | watermeter,43430778,2022-02-21,18:59:44,2022-02-21T18:59:44Z,347.075,341.179,117.73,no_alarm,no_alarm 20 | watermeter,43430778,2022-02-21,19:51:43,2022-02-21T19:51:43Z,347.107,341.179,117.73,no_alarm,no_alarm 21 | watermeter,43430778,2022-02-21,20:51:24,2022-02-21T20:51:24Z,347.177,341.179,117.73,no_alarm,no_alarm 22 | watermeter,43430778,2022-02-21,21:57:49,2022-02-21T21:57:49Z,347.185,341.179,117.73,no_alarm,no_alarm 23 | watermeter,43430778,2022-02-21,22:57:48,2022-02-21T22:57:48Z,347.21,341.179,117.73,no_alarm,no_alarm 24 | watermeter,43430778,2022-02-21,23:57:38,2022-02-21T23:57:38Z,347.226,341.179,117.73,no_alarm,no_alarm 25 | watermeter,43430778,2022-02-22,00:57:28,2022-02-22T00:57:28Z,347.226,341.179,117.73,no_alarm,no_alarm 26 | watermeter,43430778,2022-02-22,01:57:44,2022-02-22T01:57:44Z,347.226,341.179,117.73,no_alarm,no_alarm 27 | watermeter,43430778,2022-02-22,02:58:01,2022-02-22T02:58:01Z,347.226,341.179,117.73,no_alarm,no_alarm 28 | watermeter,43430778,2022-02-22,03:57:51,2022-02-22T03:57:51Z,347.226,341.179,117.73,no_alarm,no_alarm 29 | watermeter,43430778,2022-02-22,04:51:58,2022-02-22T04:51:58Z,347.234,341.179,117.73,no_alarm,no_alarm 30 | watermeter,43430778,2022-02-22,05:51:23,2022-02-22T05:51:23Z,347.235,341.179,117.73,no_alarm,no_alarm 31 | watermeter,43430778,2022-02-22,06:58:04,2022-02-22T06:58:04Z,347.26,341.179,117.73,no_alarm,no_alarm 32 | watermeter,43430778,2022-02-22,07:34:04,2022-02-22T07:34:04Z,347.27,341.179,117.73,no_alarm,No alarm 33 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:47:04Z,347.27,341.179,117.73,no_alarm,no_alarm 34 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:47:38Z,347.27,341.179,117.73,no_alarm,no_alarm 35 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:48:38Z,347.27,341.179,117.73,no_alarm,no_alarm 36 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:50:04Z,347.27,341.179,117.73,no_alarm,no_alarm 37 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:50:22Z,347.27,341.179,117.73,no_alarm,No alarm 38 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:51:21Z,347.27,341.179,117.73,no_alarm,no_alarm 39 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:51:46Z,347.27,341.179,117.73,no_alarm,no_alarm 40 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:51:55Z,347.27,341.179,117.73,no_alarm,no_alarm 41 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:52:04Z,347.27,341.179,117.73,no_alarm,no_alarm 42 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:52:47Z,347.27,341.179,117.73,no_alarm,no_alarm 43 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:52:55Z,347.271,341.179,117.73,no_alarm,no_alarm 44 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:53:12Z,347.274,341.179,117.73,no_alarm,no_alarm 45 | watermeter,43430778,2022-02-22,00:59:59,2022-02-22T07:54:29Z,347.274,341.179,117.73,no_alarm,No alarm 46 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | uptime==3.0.1 2 | paho_mqtt==1.5.1 3 | -------------------------------------------------------------------------------- /service.template: -------------------------------------------------------------------------------- 1 | [Unit] 2 | # cp service.template /etc/systemd/system/ha-watermeter.service 3 | # systemctl start ha-watermeter 4 | # systemctl enable ha-watermeter 5 | Description=Smartmeter Water data provider 6 | Documentation=https://github.com/zibous/ha-watermeter 7 | After=network.target 8 | 9 | [Service] 10 | Type=simple 11 | WorkingDirectory=/opt/ha-watermeter/ 12 | ExecStart=/usr/bin/python3 /opt/ha-watermeter/app.py 13 | StandardOutput=null 14 | 15 | 16 | StandardError=journal 17 | Environment=PYTHONUNBUFFERED=true 18 | Restart=always 19 | 20 | [Install] 21 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from datetime import datetime 5 | 6 | t = "2011-01-21 02:37:21" 7 | t = "2022-02-22 07:35:30" 8 | 9 | print(date2Local(t)) 10 | 11 | def dateToLocal(t): 12 | return datetime.fromisoformat(t) + (datetime.now() - datetime.utcnow()) 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-watermeter/85a72753f238345cfd16fbfdd78204cf673dee2b/tests/.gitkeep -------------------------------------------------------------------------------- /tests/43430778.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Wasserz\u00e4hler Haus", 3 | "device": "watermeter", 4 | "deviceid": "43430778", 5 | "date": "2020-07-15", 6 | "time": "11:57:55", 7 | "total_m3": 166.397, 8 | "m3": { 9 | "current": 0.0, 10 | "hour": 166.397, 11 | "day": 166.397, 12 | "month": 3.783, 13 | "year": 48.667 14 | }, 15 | "liter": { 16 | "current": 0.0, 17 | "hour": 166397.0, 18 | "day": 166397.0, 19 | "month": 3783.0, 20 | "year": 48667.0 21 | }, 22 | "last_total": { 23 | "hour": "13", 24 | "hour_m3": 166.397, 25 | "day": "2020-07-15", 26 | "day_m3": 165.397, 27 | "month": "2020-07", 28 | "month_m3": 162.614, 29 | "year": "2020-01-01", 30 | "year_m3": 117.73 31 | }, 32 | "alarm": "no_alarm", 33 | "last_alarm": "no_alarm", 34 | "periode": "2020-07-15", 35 | "month": "2020-07", 36 | "year": "2020", 37 | "timestamp": "2020-07-15T11:57:55Z", 38 | "last_update": "2020-07-15 13:57:55.955455", 39 | "elapsed_time": "0:00:17", 40 | "icon": "mdi:billboard", 41 | "unit_of_measurement": "\u33a5", 42 | "version": "1.0.0", 43 | "attribution": "Data provided by Peter Siebler" 44 | } -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | import time 6 | from datetime import datetime 7 | now = datetime.now() 8 | 9 | 10 | ## 2020 2020/01 2020-01-01 08:00 123,00 5,27 11 | 12 | prev_timestamp = "2020-07-15T07:34:17Z" 13 | ts = datetime.strptime(prev_timestamp ,'%Y-%m-%dT%H:%M:%SZ') 14 | current_dts = datetime.strptime("2020-07-15T07:40:17Z" ,'%Y-%m-%dT%H:%M:%SZ') 15 | 16 | print("Hour: ",current_dts.strftime('%H')) 17 | print("Day: ",current_dts.strftime('%Y-%m-%d')) 18 | print("Month: ",current_dts.strftime('%Y-%m')) 19 | print("Year: ",current_dts.strftime('%Y')) 20 | 21 | 22 | elapsed_time = current_dts - ts 23 | print("elapsed_time:" + str(elapsed_time)) 24 | 25 | 26 | data = { 27 | "name": "Wasserstand", 28 | "device": "watermeter", 29 | "deviceid": "test", 30 | "m3": { 31 | "current": 0.000, 32 | "hour": 0.000, 33 | "day": 0.000, 34 | "month": 0.000, 35 | "year": 0.000 36 | }, 37 | "liter": { 38 | "current": 0.000, 39 | "hour": 0.000, 40 | "day": 0.000, 41 | "month": 0.000, 42 | "year": 0.000 43 | }, 44 | "total_m3": 0.00, 45 | "last_month_total_m3": 0.00, 46 | "last_month_measure_date": "", 47 | "alarm": "No alarm", 48 | "last_alarm": "No alarm", 49 | "periode": now.strftime('%Y-%m-%d'), 50 | "month": now.strftime('%Y-%m'), 51 | "year": now.strftime('%Y'), 52 | "timestamp": now.strftime('%Y-%m-%d %H:%M:%S.%f'), 53 | "last_update": now.strftime('%Y-%m-%d %H:%M:%S.%f'), 54 | "icon": "mdi:billboard", 55 | "unit_of_measurement": u"\u33A5", 56 | "version": "1.0.0", 57 | "attribution": "Data provided by Peter Siebler" 58 | } 59 | 60 | with open("43430778.json", "r") as f: 61 | _prevdat = f.read() 62 | prevData = json.loads(_prevdat) 63 | 64 | if(prevData): 65 | data['m3']['current'] = round(data['total_m3'] - prevData['total_m3'],3) -------------------------------------------------------------------------------- /tests/wmbus.json: -------------------------------------------------------------------------------- 1 | { 2 | "media": "water", 3 | "meter": "izar", 4 | "name": "watermeter", 5 | "id": "43430778", 6 | "total_m3": 166.369, 7 | "last_month_total_m3": 162.614, 8 | "last_month_measure_date": "2020-07-01", 9 | "remaining_battery_life_y": 13, 10 | "current_alarms": "no_alarm", 11 | "previous_alarms": "no_alarm", 12 | "timestamp": "2020-07-15T09:03:33Z" 13 | } -------------------------------------------------------------------------------- /tools/simpleserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import sys 5 | 6 | 7 | try: 8 | import json 9 | import json 10 | import socket 11 | import time 12 | from threading import Thread 13 | 14 | except Exception as e: 15 | print(f"Configuration error {str(e)}") 16 | sys.exit(1) 17 | 18 | 19 | def getESBHomeData(url: str = "", platform: str = "sensor", id: str = "", timeout: int = 5) -> dict: 20 | """get the data from the defined platform and device id""" 21 | if url: 22 | strURL = "{}/{}/{}".format(url, platform, id) 23 | # default data 24 | dictData = { 25 | "url": strURL, 26 | "field": id, 27 | "value": -1, 28 | "state": "loading", 29 | "responsecode": 400, 30 | "responsemessage": "not found!", 31 | "encoding": "none" 32 | } 33 | response = getRequests(url=strURL, errormessage=True) 34 | if (response.status_code == 200): 35 | data = json.loads(response.text) 36 | if (data): 37 | dictData["field"] = data["id"] 38 | dictData["value"] = data["value"] 39 | dictData["state"] = "Ready" 40 | dictData["responsecode"] = response.status_code 41 | dictData["responsemessage"] = response.status_code 42 | return dictData 43 | else: 44 | dictData["state"] = "Error" 45 | dictData["value"] = float(0.00) 46 | dictData["responsecode"] = response.status_code 47 | return dictData 48 | 49 | 50 | def runUDPServer(): 51 | # https://github.com/ninedraft/python-udp/blob/master/client.py 52 | client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP 53 | client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) 54 | # Enable broadcasting mode 55 | client.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 56 | client.bind(("zeusus.siebler.home", 7227)) 57 | 58 | while True: 59 | # Thanks @seym45 for a fix 60 | data, addr = client.recvfrom(1024) 61 | if data: 62 | print("received message: %s"%data) 63 | 64 | def runRESTServer(): 65 | interval = 60 66 | next = time.time() + interval 67 | url = "http://water-meter-izar.local" 68 | 69 | while True: 70 | if time.time() >= next : 71 | data = getESBHomeData(url=url,platform="textsensor", id="watermeterdata" ) 72 | if(data): 73 | print("received message: %s"%data) 74 | next = next + interval 75 | time.sleep(next - time.time()) 76 | 77 | if __name__ == "__main__": 78 | print("Start Server") 79 | t1 = Thread(target = runUDPServer) 80 | t2 = Thread(target = runRESTServer) 81 | t1.setDaemon(True) 82 | t2.setDaemon(True) 83 | t1.start() 84 | t2.start() 85 | while True: 86 | pass --------------------------------------------------------------------------------