feat: Initial commit
This commit is contained in:
commit
135802109e
7
.env
Normal file
7
.env
Normal file
@ -0,0 +1,7 @@
|
||||
KNX_GATEWAY_IP=10.0.0.36
|
||||
KNX_TOPOLOGY=export-addresses.csv
|
||||
|
||||
INFLUX_BUCKET=my_bucket
|
||||
INFLUX_ORG=example.com
|
||||
INFLUX_TOKEN=change_me
|
||||
INFLUX_URL=http://localhost:8086
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
venv/
|
||||
requirements/
|
||||
__py*/
|
26
Dockerfile
Normal file
26
Dockerfile
Normal file
@ -0,0 +1,26 @@
|
||||
FROM python:3.10-alpine
|
||||
|
||||
WORKDIR /code/knx
|
||||
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir -r /code/requirements.txt
|
||||
|
||||
ENV KNX_GATEWAY_IP=10.0.0.36
|
||||
ENV KNX_TOPOLOGY=export-addresses.csv
|
||||
|
||||
ENV INFLUX_BUCKET=my_bucket
|
||||
ENV INFLUX_ORG=example.com
|
||||
ENV INFLUX_TOKEN=change_me
|
||||
ENV INFLUX_URL=http://localhost:8086
|
||||
|
||||
COPY ./*.py /code/knx
|
||||
COPY ./.env /code/knx
|
||||
|
||||
|
||||
ENV CONFIG_STRUCTURE=/code/data/export-addresses.csv
|
||||
|
||||
VOLUME ["/code/data/export-addresses.csv", "/code/knx/.env"]
|
||||
|
||||
|
||||
CMD ["python", "knx_monitor.py"]
|
9
LICENSE
Normal file
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Laur IVAN
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
74
README.md
Normal file
74
README.md
Normal file
@ -0,0 +1,74 @@
|
||||
# KNX monitor
|
||||
|
||||
## About
|
||||
|
||||
This program collects [KNX](https://www.knx.org/knx-en/for-your-home/) data into [InfluxDB](https://www.influxdata.com/products/influxdb-overview/)
|
||||
|
||||
## Requirements
|
||||
|
||||
You need an IP router/gateway accessible from your network. You also need InfluxDB (and [grafana](https://grafana.com/)) installed so data can be uploaded.
|
||||
|
||||
Tou also need to install the requirements:
|
||||
|
||||
```bash
|
||||
pip install --no-cache-dir -r .requirements.txt
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
You need to configure the following environment variables:
|
||||
|
||||
- `KNX_GATEWAY_IP` is the address of the gateway/router. Default value is *10.0.0.36*
|
||||
- `KNX_TOPOLOGY` is the CSV export of the group adresses. It's used to map the monitored data with types and store the proper values. It defaults to *export-addresses.csv*. PLease see below how to export the right format.
|
||||
|
||||
- `INFLUX_BUCKET` - the bucket to store the data. It defaults to *my_bucket*
|
||||
- `INFLUX_ORG` - the organisation (defined when you initialise the bucket). Defaults to *example.com*
|
||||
- `INFLUX_TOKEN` - the token to access the InfluxDB instance. Defaults to *change_me*
|
||||
- `INFLUX_URL` the URL where InfluxDB is located. It defaults to `http://localhost:8086`
|
||||
|
||||
### Export the topology
|
||||
|
||||
Here are the steps to export the topology in the proper format:
|
||||
|
||||
1. Open ETS
|
||||
1. Open your project
|
||||
1. Open a **Group Addresses** panel
|
||||
1. Right clock on the top **Group Addresses** (just above *Dynamic Folders*)
|
||||
1. Click on **Export Group Addresses**
|
||||
1. Choose **CSV Format**, **1/1 Name/Address** with a **Semicolon** CSV Separator
|
||||
1. Select a file name to store the result
|
||||
1. click "OK"
|
||||
|
||||
You should have a CSV file like:
|
||||
|
||||
```csv
|
||||
"Group name";"Address";"Central";"Unfiltered";"Description";"DatapointType";"Security"
|
||||
"Cellar - HVAC";"0/-/-";"";"";"";"";"Auto"
|
||||
"Media - HVAC";"0/3/-";"";"";"";"";"Auto"
|
||||
"Valve1-1 Media [CTEMP 1.3.10]";"0/3/6";"";"";"Wellness Lounge H";"DPST-9-1";"Auto"
|
||||
"Valve1-1 Media [SETPOINT TEMP]";"0/3/7";"";"";"Wellness Lounge H";"DPST-9-1";"Auto"
|
||||
"Valve1-1 Media [CMD]";"0/3/8";"";"";"Wellness Lounge H";"DPST-5-1";"Auto"
|
||||
"Valve1-1 Media [OP]";"0/3/9";"";"";"Wellness Lounge H";"DPST-20-102";"Auto"
|
||||
```
|
||||
|
||||
### Launch
|
||||
|
||||
You can either use the command line:
|
||||
|
||||
```shell
|
||||
python3 knx_monitor
|
||||
```
|
||||
|
||||
or use the provided docker image. In this case, please make sure you set the read-only volume to the export file
|
||||
|
||||
```shell
|
||||
-v /path/to/your/export.csv:/code/data/export-addresses.csv
|
||||
```
|
||||
|
||||
You can either define the above environment variables, or create a .env file and map it via
|
||||
|
||||
```shell
|
||||
-v /path/to/your/envfile:/code/knx/.env
|
||||
```
|
||||
|
||||
HTH
|
20
db.py
Normal file
20
db.py
Normal file
@ -0,0 +1,20 @@
|
||||
import influxdb_client
|
||||
from influxdb_client.client.write_api import SYNCHRONOUS
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
dotenv_path = join(dirname(__file__), '.env')
|
||||
load_dotenv(dotenv_path)
|
||||
|
||||
bucket=os.environ.get('INFLUX_BUCKET')
|
||||
org=os.environ.get('INFLUX_ORG')
|
||||
token=os.environ.get('INFLUX_TOKEN')
|
||||
url=os.environ.get('INFLUX_URL')
|
||||
|
||||
client = influxdb_client.InfluxDBClient(url=url, token=token, org=org)
|
||||
write_api = client.write_api(write_options=SYNCHRONOUS)
|
||||
|
||||
|
||||
def publish_measurement(value):
|
||||
p = influxdb_client.Point(f'KNX-{value["type"]}').tag("name", f'{value["name"]}').tag("destination", f'{value["destination"]}').tag("description", f'{value["description"]}').field("value", value["value"])
|
||||
write_api.write(bucket=bucket, org=org, record=p)
|
222
export-addresses-guest-12-12.csv
Normal file
222
export-addresses-guest-12-12.csv
Normal file
@ -0,0 +1,222 @@
|
||||
"Group name";"Address";"Central";"Unfiltered";"Description";"DatapointType";"Security"
|
||||
"Cellar - HVAC";"0/-/-";"";"";"";"";"Auto"
|
||||
"Media - HVAC";"0/3/-";"";"";"";"";"Auto"
|
||||
"Valve1-1 Media [CTEMP 1.3.10]";"0/3/6";"";"";"Wellness Lounge H";"DPST-9-1";"Auto"
|
||||
"Valve1-1 Media [SETPOINT TEMP]";"0/3/7";"";"";"Wellness Lounge H";"DPST-9-1";"Auto"
|
||||
"Valve1-1 Media [CMD]";"0/3/8";"";"";"Wellness Lounge H";"DPST-5-1";"Auto"
|
||||
"Valve1-1 Media [OP]";"0/3/9";"";"";"Wellness Lounge H";"DPST-20-102";"Auto"
|
||||
"Wellness - HVAC";"0/5/-";"";"";"";"";"Auto"
|
||||
"Valve1-2 Lounge [CTEMP 2.3.1]";"0/5/2";"";"";"Wellness HVAC - Lounge";"DPST-9-1";"Auto"
|
||||
"Valve1-2 Lounge [SETPOINT TEMP]";"0/5/3";"";"";"Wellness HVAC - Lounge";"DPST-9-1";"Auto"
|
||||
"Valve1-2 Lounge [CMD]";"0/5/4";"";"";"Wellness HVAC - Lounge";"DPST-5-1";"Auto"
|
||||
"Valve1-2 Lounge [OP]";"0/5/5";"";"";"Wellness HVAC - Lounge";"DPST-20-102";"Auto"
|
||||
"Ground floor";"2/-/-";"";"";"";"";"Auto"
|
||||
"Dining";"2/3/-";"";"";"";"";"Auto"
|
||||
"Lights1-1[78] Dining all lights [SW]";"2/3/4";"";"";"Dining room All";"DPST-1-1";"Auto"
|
||||
"Lights1-1[78] Dining all lights [FB]";"2/3/5";"";"";"Dining room All";"DPST-1-1";"Auto"
|
||||
"Living";"2/6/-";"";"";"";"";"Auto"
|
||||
"Lights1-[16,18,20,21] Living all [SW]";"2/6/8";"";"";"Living room All";"DPST-1-1";"Auto"
|
||||
"Lights1-[16,18,20,21] Living all [FB]";"2/6/9";"";"";"Living room All";"DPST-1-1";"Auto"
|
||||
"First floor - HVAC";"3/-/-";"";"";"";"";"Auto"
|
||||
"Master bed - HVAC";"3/1/-";"";"";"";"";"Auto"
|
||||
"Valve2-2 Master bed [CTEMP 2.2.1]";"3/1/14";"";"";"Master HVAC";"DPST-9-1";"Auto"
|
||||
"Valve2-2 Master bed [SETPOINT TEMP]";"3/1/15";"";"";"Master HVAC";"DPST-9-1";"Auto"
|
||||
"Valve2-2 Master bed [CMD]";"3/1/16";"";"";"Master HVAC";"DPST-5-1";"Auto"
|
||||
"Valve2-2 Master bed [OP]";"3/1/17";"";"";"Master HVAC";"DPST-20-102";"Auto"
|
||||
"Bathroom - HVAC";"3/2/-";"";"";"";"";"Auto"
|
||||
"Valve2-1 Bathroom [CTEMP 2.2.3]";"3/2/6";"";"";"Bathroom HVAC Bath";"DPST-9-1";"Auto"
|
||||
"Valve2-1 Bathroom [SETPOINT TEMP]";"3/2/7";"";"";"Bathroom HVAC Bath";"DPST-9-1";"Auto"
|
||||
"Valve2-1 Bathroom [CMD]";"3/2/8";"";"";"Bathroom HVAC Bath";"DPST-5-1";"Auto"
|
||||
"Valve2-1 Bathroom [OP]";"3/2/9";"";"";"Bathroom HVAC Bath";"DPST-20-102";"Auto"
|
||||
"Child - HVAC";"3/3/-";"";"";"";"";"Auto"
|
||||
"Valve2-4 Child [CTEMP 2.2.2]";"3/3/6";"";"";"Child HVAC Child";"DPST-9-1";"Auto"
|
||||
"Valve2-4 Child [SETPOINT TEMP]";"3/3/7";"";"";"Child HVAC Child";"DPST-9-1";"Auto"
|
||||
"Valve2-4 Child [CMD]";"3/3/8";"";"";"Child HVAC Child";"DPST-5-1";"Auto"
|
||||
"Valve2-4 Child [OP]";"3/3/9";"";"";"Child HVAC Child";"DPST-20-102";"Auto"
|
||||
"Study - HVAC";"3/5/-";"";"";"";"";"Auto"
|
||||
"Valve2-3 Study [CTEMP 2.2.4]";"3/5/6";"";"";"Study HVAC";"DPST-9-1";"Auto"
|
||||
"Valve2-3 Study [SETPOINT TEMP]";"3/5/7";"";"";"Study HVAC";"DPST-9-1";"Auto"
|
||||
"Valve2-3 Study [CMD]";"3/5/8";"";"";"Study HVAC";"DPST-5-1";"Auto"
|
||||
"Valve2-3 Study [OP]";"3/5/9";"";"";"Study HVAC";"DPST-20-102";"Auto"
|
||||
"HVAC";"4/-/-";"";"";"";"";"Auto"
|
||||
"Media Room";"4/0/-";"";"";"";"";"Auto"
|
||||
"In house";"4/0/0";"";"";"";"DPST-20-102";"Auto"
|
||||
"21 degrees rooms";"4/0/1";"";"";"";"DPST-9-1";"Auto"
|
||||
"23 degrees bathrooms";"4/0/2";"";"";"";"DPST-9-1";"Auto"
|
||||
"Presence led";"4/0/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"UG Media";"4/0/4";"";"";"";"DPST-5-1";"Auto"
|
||||
"UG Lounge";"4/0/5";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Shower";"4/0/6";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Dining";"4/0/7";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Living";"4/0/8";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Guest";"4/0/9";"";"";"";"DPST-5-1";"Auto"
|
||||
"All valves";"4/0/101";"";"";"";"DPST-5-1";"Auto"
|
||||
"Setpoint temperature";"4/2/-";"";"";"";"";"Auto"
|
||||
"UG Media";"4/2/0";"";"";"";"DPST-9-1";"Auto"
|
||||
"UG Lounge";"4/2/1";"";"";"";"DPST-9-1";"Auto"
|
||||
"GF - Shower";"4/2/2";"";"";"";"DPST-9-1";"Auto"
|
||||
"GF - Dining";"4/2/3";"";"";"";"DPST-9-1";"Auto"
|
||||
"GF - Living";"4/2/4";"";"";"";"DPST-9-1";"Auto"
|
||||
"GF - Guest";"4/2/5";"";"";"";"DPST-9-1";"Auto"
|
||||
"FF - Master bed";"4/2/6";"";"";"";"DPST-9-1";"Auto"
|
||||
"FF - Child";"4/2/7";"";"";"";"DPST-9-1";"Auto"
|
||||
"Valve position";"4/3/-";"";"";"";"";"Auto"
|
||||
"UG Media";"4/3/0";"";"";"";"DPST-5-1";"Auto"
|
||||
"UG Lounge";"4/3/1";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Shower";"4/3/2";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Dining";"4/3/3";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Living";"4/3/4";"";"";"";"DPST-5-1";"Auto"
|
||||
"GF - Guest";"4/3/5";"";"";"";"DPST-5-1";"Auto"
|
||||
"FF - Master bed";"4/3/6";"";"";"";"DPST-5-1";"Auto"
|
||||
"FF - Child";"4/3/7";"";"";"";"DPST-5-1";"Auto"
|
||||
"UG - Building based";"5/-/-";"";"";"";"";"Auto"
|
||||
"Scene";"5/0/-";"";"";"";"";"Auto"
|
||||
"Lights1-[567] - Media all lights SW";"5/0/0";"";"";"Media all lamps switching feedback";"DPST-1-1";"Auto"
|
||||
"Lights1-[567] - Media all lights FB";"5/0/1";"";"";"Media all lamps switching feedback
|
||||
Sender done via NodeRed.";"DPST-1-1";"Auto"
|
||||
"Lighting";"5/1/-";"";"";"";"";"Auto"
|
||||
"Lights1-1 Tech room SW";"5/1/0";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-1 Tech room FB";"5/1/1";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-2 Storage SW";"5/1/2";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-2 Storage FB";"5/1/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-3 Server SW";"5/1/4";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-3 Server FB";"5/1/5";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-4 Hall SW";"5/1/6";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-4 Hall FB";"5/1/7";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-5 Media back SW";"5/1/8";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-5 Media back FB";"5/1/9";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-6 Media mid SW";"5/1/10";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-6 Media mid FB";"5/1/11";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-7 Media front SW";"5/1/12";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-7 Media front FB";"5/1/13";"";"";"";"DPST-1-1";"Auto"
|
||||
"Shutter";"5/2/-";"";"";"";"";"Auto"
|
||||
"Heating";"5/3/-";"";"";"";"";"Auto"
|
||||
"Timers";"5/4/-";"";"";"";"";"Auto"
|
||||
"GF - Building Based";"6/-/-";"";"";"";"";"Auto"
|
||||
"Scene";"6/0/-";"";"";"";"";"Auto"
|
||||
"Lights1-2[34] Shower, all lights [SW]";"6/0/0";"";"";"Shower both lamps switching";"DPST-1-1";"Auto"
|
||||
"Lights1-2[34] Shower, all lights [FB]";"6/0/1";"";"";"Shower both lamps switching feedback
|
||||
Feedback received via NodeRed";"DPST-1-1";"Auto"
|
||||
"Lights1-1[45] Kitchen, all lights [SW]";"6/0/2";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-1[45] Kitchen, all lights [FB]";"6/0/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights[1-13,2-13] Hallway [SW]";"6/0/4";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights[1-13,2-13] Hallway [FB]";"6/0/5";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lighting";"6/1/-";"";"";"";"";"Auto"
|
||||
"Lights1-8 Guest, Ceiling lamp [SW]";"6/1/0";"";"";"Guest ceiling lamp switching";"DPST-1-1";"Auto"
|
||||
"Lights1-8 Guest, Ceiling lamp [FB]";"6/1/1";"";"";"Guest ceiling lamp switching feedback";"DPST-1-1";"Auto"
|
||||
"Lights1-23 Shower, Ceiling lamp [SW]";"6/1/2";"";"";"Shower ceiling lamp switching";"DPST-1-1";"Auto"
|
||||
"Lights1-23 Shower, Ceiling lamp [FB]";"6/1/3";"";"";"Shower ceiling lamp switching feedback";"DPST-1-1";"Auto"
|
||||
"Lights1-24 Shower, Mirror lamp [SW]";"6/1/4";"";"";"Shower mirror lamp switching";"DPST-1-1";"Auto"
|
||||
"Lights1-24 Shower, Mirror lamp [FB]";"6/1/5";"";"";"Shower mirror lamp switching";"DPST-1-1";"Auto"
|
||||
"Lights1-9 Storage, Ceiling lamp [SW]";"6/1/6";"";"";"Storage ceiling lamps switching";"DPST-1-1";"Auto"
|
||||
"Lights1-9 Storage, Ceiling lamp [FB]";"6/1/7";"";"";"Storage ceiling lamps feedback";"DPST-1-1";"Auto"
|
||||
"Lights1-14 Kitchen ceiling [SW]";"6/1/8";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-14 Kitchen ceiling [FB]";"6/1/9";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-22 Staircase [SW]";"6/1/10";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-22 Staircase [FB]";"6/1/11";"";"";"";"DPST-1-1";"Auto"
|
||||
"Light1-14 Kitchen rail [SW]";"6/1/12";"";"";"";"DPST-1-1";"Auto"
|
||||
"Light1-14 Kitchen rail [FB]";"6/1/13";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-17 Dining rail [SW]";"6/1/14";"";"";"Dining room Beam";"DPST-1-1";"Auto"
|
||||
"Lights1-17 Dining rail [FB]";"6/1/15";"";"";"Dining room Beam";"DPST-1-1";"Auto"
|
||||
"Lights1-18 Dining top [SW]";"6/1/16";"";"";"Dining room Top";"DPST-1-1";"Auto"
|
||||
"Lights1-18 Dining top [FB]";"6/1/17";"";"";"Dining room Top";"DPST-1-1";"Auto"
|
||||
"Lights1-16 Living hall [SW]";"6/1/18";"";"";"Living room Living hall";"DPST-1-1";"Auto"
|
||||
"Lights1-16 Living hall [FB]";"6/1/19";"";"";"Living room Living hall";"DPST-1-1";"Auto"
|
||||
"Lights1-19 Living main [SW]";"6/1/20";"";"";"Living room Living main";"DPST-1-1";"Auto"
|
||||
"Lights1-19 Living main [FB]";"6/1/21";"";"";"Living room Living main";"DPST-1-1";"Auto"
|
||||
"Lights1-20 Living beam [SW]";"6/1/22";"";"";"Living room Living rail";"DPST-1-1";"Auto"
|
||||
"Lights1-20 Living beam [FB]";"6/1/23";"";"";"Living room Living rail";"DPST-1-1";"Auto"
|
||||
"Lights1-21 Living back [SW]";"6/1/24";"";"";"Living room Living accent";"DPST-1-1";"Auto"
|
||||
"Lights1-21 Living back [FB]";"6/1/25";"";"";"Living room Living accent";"DPST-1-1";"Auto"
|
||||
"Shutter";"6/2/-";"";"";"";"";"Auto"
|
||||
"HVAC";"6/3/-";"";"";"";"";"Auto"
|
||||
"Valve1 - 6 Living heating [CTEMP 2.1.11]";"6/3/0";"";"";"Living accents";"DPST-9-1";"Auto"
|
||||
"Valve1 - 6 Living heating [CTEMP 2.1.13]";"6/3/1";"";"";"Living stairs";"DPST-9-1";"Auto"
|
||||
"Valve1 - 6 Living heating [CTEMP 2.1.10]";"6/3/2";"";"";"Living main";"DPST-9-1";"Auto"
|
||||
"Valve1 - 6 Living heating [CMD]";"6/3/3";"";"";"Living room HVAC";"DPST-5-1";"Auto"
|
||||
"Valve1 - 6 Living heating [SETPOINT TEMP]";"6/3/4";"";"";"Living room HVAC";"DPST-9-1";"Auto"
|
||||
"Valve1 - 6 Living heating [OP]";"6/3/5";"";"";"Living room HVAC";"DPST-20-102";"Auto"
|
||||
"Valve1 - 5 Dining heating [CTEMP 2.1.8]";"6/3/6";"";"";"Dining thermo";"DPST-9-1";"Auto"
|
||||
"Valve1 - 5 Dining heating [CTEMP 2.1.9]";"6/3/7";"";"";"Dining door";"DPST-9-1";"Auto"
|
||||
"Valve1 - 5 Dining heating [CMD]";"6/3/8";"";"";"Dining room HVAC";"DPST-5-1";"Auto"
|
||||
"Valve1 - 5 Dining heating [SETPOINT TEMP]";"6/3/9";"";"";"Dining room HVAC";"DPST-9-1";"Auto"
|
||||
"Valve1 - 5 Dining heating [OP]";"6/3/10";"";"";"Dining room HVAC";"DPST-20-102";"Auto"
|
||||
"Valve1-4 Shower [CTEMP 2.1.7]";"6/3/11";"";"";"Shower";"DPST-9-1";"Auto"
|
||||
"Valve1-4 Shower [CMD]";"6/3/12";"";"";"Shower HVAC";"DPST-5-1";"Auto"
|
||||
"Valve1-4 Shower [STEPOINT TEMP]";"6/3/13";"";"";"Shower HVAC";"DPST-9-1";"Auto"
|
||||
"Valve1-4 Shower [OP]";"6/3/14";"";"";"Shower HVAC";"DPST-20-102";"Auto"
|
||||
"Valve1-3 Guest [CTEMP 2.1.1]";"6/3/15";"";"";"Guest room";"DPST-9-1";"Auto"
|
||||
"Valve1-3 Guest [STEPOINT TEMP]";"6/3/16";"";"";"Guest room HVAC - Guest";"DPST-9-1";"Auto"
|
||||
"Valve1-3 Guest [CMD]";"6/3/17";"";"";"Guest room HVAC - Guest";"DPST-5-1";"Auto"
|
||||
"Valve1-3 Guest [OP]";"6/3/18";"";"";"Guest room HVAC - Guest";"DPST-20-102";"Auto"
|
||||
"Valve1-X Entrance [CTEMP 2.1.2]";"6/3/19";"";"";"Entrance";"DPST-9-1";"Auto"
|
||||
"Valve1-X Entrance [CTEMP 2.1.3]";"6/3/20";"";"";"Hallway";"DPST-9-1";"Auto"
|
||||
"Valve1-X Storage [CTEMP 2.1.4]";"6/3/21";"";"";"Storage";"DPST-9-1";"Auto"
|
||||
"Valve1-X Kitchen [CTEMP 2.1.5]";"6/3/22";"";"";"Kitchen entrance";"DPST-9-1";"Auto"
|
||||
"Valve1-X Stairway [CTEMP 2.1.6]";"6/3/23";"";"";"Stairway GF";"DPST-9-1";"Auto"
|
||||
"Valve1-X Slider [CTEMP 2.1.12]";"6/3/24";"";"";"Slider";"DPST-9-1";"Auto"
|
||||
"Valve1-X Kitchen front [CTEMP 2.1.14]";"6/3/25";"";"";"Kitchen front";"DPST-9-1";"Auto"
|
||||
"Timers";"6/4/-";"";"";"";"";"Auto"
|
||||
"Current Time";"6/4/0";"";"";"";"DPST-10-1";"Auto"
|
||||
"Led night reduction - Guest";"6/4/1";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Hallway";"6/4/2";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Shower";"6/4/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Kitchen";"6/4/4";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Dining";"6/4/5";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Living";"6/4/6";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Stairs";"6/4/7";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Storage";"6/4/8";"";"";"";"DPST-1-1";"Auto"
|
||||
"FF - Building Based";"7/-/-";"";"";"";"";"Auto"
|
||||
"Scene";"7/0/-";"";"";"";"";"Auto"
|
||||
"Lights2-[567] Master bed, all lights SW";"7/0/0";"";"";"Master bedroom all lamps switching feedback";"DPST-1-1";"Auto"
|
||||
"Lights2-[567] Master bed, all lights FB";"7/0/1";"";"";"Master bedroom all lamps switching feedback
|
||||
Feedback received via NodeRed";"DPST-1-1";"Auto"
|
||||
"Lights2-[4,11] Study all lights SW";"7/0/2";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-[4,11] Study all lights FB";"7/0/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lighting";"7/1/-";"";"";"";"";"Auto"
|
||||
"Lights2-7 Master bed Ceiling 1 SW";"7/1/0";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-7 Master bed Ceiling 1 FB";"7/1/1";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-6 Master bed Ceiling 2 SW";"7/1/2";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-6 Master bed Ceiling 2 FB";"7/1/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-5 Master bed Beam SW";"7/1/4";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-5 Master bed Beam FB";"7/1/5";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-8 Storage SW";"7/1/6";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-8 Storage FB";"7/1/7";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-15 Bath Rail SW";"7/1/8";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-15 Bath Rail FB";"7/1/9";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-15 Bath mirror backlit SW";"7/1/10";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-15 Bath mirror backlit FB";"7/1/11";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-15 Bath focus SW";"7/1/12";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-15 Bath focus FB";"7/1/13";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-1 Kid rail SW";"7/1/14";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-1 Kid rail FB";"7/1/15";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-1 Kid ceiling SW";"7/1/16";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-1 Kid ceiling FB";"7/1/17";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-1 Kid wall SW";"7/1/18";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-1 Kid wall FB";"7/1/19";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-12 Hallway SW";"7/1/20";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-12 Hallway FB";"7/1/21";"";"";"";"DPST-1-1";"Auto"
|
||||
"Light2-4 Study rail SW";"7/1/22";"";"";"";"DPST-1-1";"Auto"
|
||||
"Light2-4 Study rail FB";"7/1/23";"";"";"";"DPST-1-1";"Auto"
|
||||
"Light11-4 Study stairs SW";"7/1/24";"";"";"";"DPST-1-1";"Auto"
|
||||
"Light11-4 Study stairs FB";"7/1/25";"";"";"";"DPST-1-1";"Auto"
|
||||
"Shutter";"7/2/-";"";"";"";"";"Auto"
|
||||
"Heating";"7/3/-";"";"";"";"";"Auto"
|
||||
"Timers";"7/4/-";"";"";"";"";"Auto"
|
||||
"Led night reduction - Master bed";"7/4/0";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Child bed";"7/4/1";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Open space";"7/4/2";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Bathroom";"7/4/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"Led night reduction - Storage";"7/4/4";"";"";"";"DPST-1-1";"Auto"
|
||||
"Outside - Building based";"8/-/-";"";"";"";"";"Auto"
|
||||
"Scene";"8/0/-";"";"";"";"";"Auto"
|
||||
"Lighting";"8/1/-";"";"";"";"";"Auto"
|
||||
"Lights1-10 Out left SW";"8/1/0";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-10 Out left FB";"8/1/1";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-14 Out entrance SW";"8/1/2";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights2-14 Out entrance FB";"8/1/3";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-10,2-14 Out SW";"8/1/4";"";"";"";"DPST-1-1";"Auto"
|
||||
"Lights1-10,2-14 Out FB";"8/1/5";"";"";"";"DPST-1-1";"Auto"
|
||||
"Shutter";"8/2/-";"";"";"";"";"Auto"
|
||||
"Heating";"8/3/-";"";"";"";"";"Auto"
|
||||
"Timers";"8/4/-";"";"";"";"";"Auto"
|
|
82
knx_monitor.py
Normal file
82
knx_monitor.py
Normal file
@ -0,0 +1,82 @@
|
||||
"""Example for the telegram monitor callback."""
|
||||
import asyncio
|
||||
import getopt
|
||||
import sys
|
||||
|
||||
from xknx import XKNX
|
||||
from xknx.io import ConnectionConfig, ConnectionType
|
||||
from xknx.telegram import AddressFilter
|
||||
from structure import parse_message, load_structure, init_value_mapping
|
||||
import json
|
||||
|
||||
from dotenv import load_dotenv
|
||||
dotenv_path = join(dirname(__file__), '.env')
|
||||
load_dotenv(dotenv_path)
|
||||
|
||||
from db import publish_measurement
|
||||
|
||||
config = {}
|
||||
mapping = {}
|
||||
|
||||
|
||||
|
||||
|
||||
async def telegram_received_cb(telegram):
|
||||
"""Do something with the received telegram."""
|
||||
val = parse_message(config, mapping, telegram)
|
||||
publish_measurement(val)
|
||||
|
||||
|
||||
def show_help():
|
||||
"""Print Help."""
|
||||
print("Telegram filter.")
|
||||
print("")
|
||||
print("Usage:")
|
||||
print("")
|
||||
print(__file__, " Listen to all telegrams")
|
||||
print(
|
||||
__file__, "-f --filter 1/2/*,1/4/[5-6] Filter for specific group addresses"
|
||||
)
|
||||
print(__file__, "-h --help Print help")
|
||||
print("")
|
||||
|
||||
|
||||
async def monitor(address_filters):
|
||||
"""Set telegram_received_cb within XKNX and connect to KNX/IP device in daemon mode."""
|
||||
connection_config = ConnectionConfig(
|
||||
connection_type=ConnectionType.TUNNELING,
|
||||
gateway_ip=os.environ.get('KNX_GATEWAY_IP')
|
||||
)
|
||||
xknx = XKNX(connection_config=connection_config, daemon_mode=True)
|
||||
xknx.telegram_queue.register_telegram_received_cb(
|
||||
telegram_received_cb, address_filters
|
||||
)
|
||||
await xknx.start()
|
||||
await xknx.stop()
|
||||
|
||||
|
||||
async def main(argv):
|
||||
"""Parse command line arguments and start monitor."""
|
||||
try:
|
||||
opts, _ = getopt.getopt(argv, "hf:", ["help", "filter="])
|
||||
except getopt.GetoptError:
|
||||
show_help()
|
||||
sys.exit(2)
|
||||
|
||||
global config
|
||||
config = load_structure(os.environ.get('KNX_TOPOLOGY'))
|
||||
global mapping
|
||||
mapping = init_value_mapping()
|
||||
|
||||
address_filters = None
|
||||
for opt, arg in opts:
|
||||
if opt in ["-h", "--help"]:
|
||||
show_help()
|
||||
sys.exit()
|
||||
if opt in ["-f", "--filter"]:
|
||||
address_filters = list(map(AddressFilter, arg.split(",")))
|
||||
await monitor(address_filters)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main(sys.argv[1:]))
|
20
requirements.txt
Normal file
20
requirements.txt
Normal file
@ -0,0 +1,20 @@
|
||||
certifi==2022.12.7
|
||||
cffi==1.15.1
|
||||
charset-normalizer==2.1.1
|
||||
cryptography==38.0.4
|
||||
idna==3.4
|
||||
ifaddr==0.2.0
|
||||
influxdb==5.3.1
|
||||
influxdb-client==1.35.0
|
||||
json-fix==0.5.1
|
||||
msgpack==1.0.4
|
||||
pycparser==2.21
|
||||
python-dateutil==2.8.2
|
||||
python-dotenv==0.21.0
|
||||
pytz==2022.6
|
||||
reactivex==4.0.4
|
||||
requests==2.28.1
|
||||
six==1.16.0
|
||||
typing-extensions==4.4.0
|
||||
urllib3==1.26.13
|
||||
xknx==2.1.0
|
105
structure.py
Normal file
105
structure.py
Normal file
@ -0,0 +1,105 @@
|
||||
import csv
|
||||
import json
|
||||
import json_fix
|
||||
|
||||
import xknx.remote_value
|
||||
import xknx
|
||||
from xknx.dpt import DPT2ByteFloat, DPTBinary, DPTTime, DPTValue1ByteUnsigned
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
class DPST:
|
||||
def __init__(self, str):
|
||||
vals = str.split('-')
|
||||
self.major = vals[1]
|
||||
self.minor = vals[2]
|
||||
|
||||
def __str__(self):
|
||||
return f"DPST {self.major}.{self.minor}"
|
||||
|
||||
def __json__(self, **options):
|
||||
return self.__dict__
|
||||
|
||||
class Endpoint:
|
||||
def __init__(self, name, address, central, unfiltered, description, dpt, security, *args, **kwargs):
|
||||
self.name = name
|
||||
self.address = address
|
||||
self.central = central
|
||||
self.unfiltered = unfiltered
|
||||
self.description = description
|
||||
|
||||
if self.is_endpoint():
|
||||
self.dpt = DPST(dpt)
|
||||
else:
|
||||
self.dpt = None
|
||||
self.security = security
|
||||
|
||||
def is_endpoint(self):
|
||||
return self.address[-1] != '-'
|
||||
|
||||
def __str__(self):
|
||||
return f"name: {self.name}, address: {self.address}, dpt: {self.dpt}"
|
||||
|
||||
def __json__(self, **options):
|
||||
return self.__dict__
|
||||
|
||||
|
||||
def init_value_mapping():
|
||||
config = {}
|
||||
config['1'] = { "value": DPTBinary, "type": "number" }
|
||||
config['9'] = { "value": DPT2ByteFloat, "type": "number" }
|
||||
config['10'] = { "value": DPTTime, "type": "time" }
|
||||
config['5'] = { "value": DPTValue1ByteUnsigned, "type": "number" }
|
||||
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def load_structure(filename):
|
||||
config = {}
|
||||
with open(filename, newline='') as csvFile:
|
||||
line = 0
|
||||
reader = csv.reader(csvFile, delimiter=';', quotechar='"')
|
||||
for row in reader:
|
||||
line += 1
|
||||
if line == 1:
|
||||
continue
|
||||
c = Endpoint(*row)
|
||||
if c.is_endpoint():
|
||||
if c.dpt == '':
|
||||
print(f"Unknown DPT format for {c.address} ({c.name})")
|
||||
config[c.address] = c
|
||||
return config
|
||||
|
||||
def parse_message(structure, mapping, telegram):
|
||||
if f"{telegram.destination_address}" not in structure:
|
||||
print(f"Unrecognised address {telegram.destination_address}. ignoring")
|
||||
return
|
||||
hit = structure[f"{telegram.destination_address}"]
|
||||
try:
|
||||
value = mapping[hit.dpt.major]["value"].from_knx(telegram.payload.value.value)
|
||||
|
||||
# Convert the value to something else if needed
|
||||
#
|
||||
if mapping[hit.dpt.major]["type"] == "time":
|
||||
value = value.tm_hour*3600+value.tm_min*60 +value.tm_sec
|
||||
|
||||
return {
|
||||
"timestamp": datetime.now().timestamp(),
|
||||
"value": value,
|
||||
"destination": f"{telegram.destination_address}",
|
||||
"name": hit.name,
|
||||
"description": hit.description,
|
||||
"type": f"{hit.dpt}"
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Unmapped {hit.dpt}")
|
||||
print (e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from dotenv import load_dotenv
|
||||
dotenv_path = join(dirname(__file__), '.env')
|
||||
load_dotenv(dotenv_path)
|
||||
config = load_structure(os.environ.get('KNX_TOPOLOGY'))
|
||||
print(json.dumps(config["6/4/0"], indent=2))
|
Loading…
Reference in New Issue
Block a user