initial commit from old development
This commit is contained in:
236
BSHGateWay.py
Normal file
236
BSHGateWay.py
Normal file
@@ -0,0 +1,236 @@
|
||||
#!/usr/bin/python
|
||||
#Bosch Home Automation <> MQTT Gateway
|
||||
|
||||
import requests, json, time
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
#Suppress http request warning
|
||||
import urllib3
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
class BSH:
|
||||
#BSH Settings
|
||||
IP_SHC = "192.168.178.20"
|
||||
baseurl = 'https://' + IP_SHC + ':8444'
|
||||
url = baseurl + '/remote/json-rpc'
|
||||
states = ["childLock","value","position","armActivationDelayTime","alarmActivationDelayTime",
|
||||
"walkState","petImmunityState","quality","faults","triggers","actuators","remainingTimeUntilArmed",
|
||||
"state","path","enabled","devices","path","runningStartTime","runningEndTime","operationMode",
|
||||
"setpointTemperature","setpointTemperatureForLevelComfort","setpointTemperatureForLevelEco",
|
||||
"schedule","ventilationMode","low","boostMode","summerMode","on","calibrated","movingTimeTopToBottom",
|
||||
"movingTimeBottomToTop","level","operationState","deviceId","switchState","operationMode",
|
||||
"powerConsumption","energyConsumption","delay"]
|
||||
|
||||
#Mosquitto Settings
|
||||
client_name = "BSH_Mosquitto_Client"
|
||||
host_name = "192.168.178.36"
|
||||
|
||||
session = requests.Session()
|
||||
AutomationRules = {}
|
||||
DicAutomationRules = {}
|
||||
|
||||
Devices = {}
|
||||
DicDevices = {}
|
||||
|
||||
Scenarios = {}
|
||||
DicScenarios = {}
|
||||
|
||||
Rooms = {}
|
||||
DicRooms = {}
|
||||
|
||||
client = mqtt.Client(client_name)
|
||||
|
||||
#get URL Headers
|
||||
def getURLHeaders(self):
|
||||
return {'Content-Type' : 'application/json'}
|
||||
|
||||
def getCertificate(self):
|
||||
return ("./example-cert.pem","./example-key.pem")
|
||||
|
||||
#subscribe to Long Polling
|
||||
def subscribe(self):
|
||||
payload = [
|
||||
{
|
||||
"jsonrpc":"2.0",
|
||||
"method":"RE/subscribe",
|
||||
"id":"randomid",
|
||||
"params": ["com/bosch/sh/remote/*", None]
|
||||
}
|
||||
]
|
||||
return self.shc_request(payload)
|
||||
|
||||
#Start Long Polling and keep it 2 seconds open
|
||||
def poll(self,pollId):
|
||||
payload = [
|
||||
{
|
||||
"jsonrpc":"2.0",
|
||||
"method":"RE/longPoll",
|
||||
"id":"randomid",
|
||||
"params": [pollId, 2]
|
||||
}
|
||||
]
|
||||
return self.shc_request(payload)
|
||||
|
||||
#Post Polling data to SHC
|
||||
def shc_request(self,payload):
|
||||
postRequest = requests.post(self.url, data=json.dumps(payload), headers = self.getURLHeaders(),
|
||||
verify = False, cert = self.getCertificate())
|
||||
return json.loads(postRequest.text)[0]['result']
|
||||
|
||||
#Sent MQTT Debugging Message
|
||||
def publishDebugMsg(self,msg):
|
||||
self.client.publish("bsh/debug",msg,0,True)
|
||||
|
||||
#Get all BSH Decives
|
||||
def getDevices(self):
|
||||
getRequest = self.session.get("https://"+self.IP_SHC+":8444/smarthome/devices", verify=False,
|
||||
cert = self.getCertificate(), headers = self.getURLHeaders())
|
||||
return json.loads(getRequest.content)
|
||||
|
||||
|
||||
#Get all BSH automation rules
|
||||
def getAutomationRules(self):
|
||||
getRequest = self.session.get("https://"+self.IP_SHC+":8444/smarthome/automation/rules", verify=False,
|
||||
cert = self.getCertificate(), headers = self.getURLHeaders())
|
||||
return json.loads(getRequest.content)
|
||||
|
||||
#Get all BSH scenarios
|
||||
def getScenarios(self):
|
||||
getRequest = self.session.get("https://"+self.IP_SHC+":8444/smarthome/scenarios", verify=False,
|
||||
cert = self.getCertificate(), headers = self.getURLHeaders())
|
||||
return json.loads(getRequest.content)
|
||||
|
||||
#Get all BSH rooms
|
||||
def getRooms(self):
|
||||
getRequest = self.session.get("https://"+self.IP_SHC+":8444/smarthome/rooms", verify=False,
|
||||
cert = self.getCertificate(), headers = self.getURLHeaders())
|
||||
contents = getRequest.content
|
||||
return json.loads(contents)
|
||||
|
||||
#Generate a topic name for a device
|
||||
def getTopicBase(self,dev):
|
||||
topic = ""
|
||||
if "roomId" in dev:
|
||||
topic = "bsh/"+self.DicRooms[dev["roomId"]]["name"]+"/"+dev["name"].replace(" ","_")+"/"
|
||||
else:
|
||||
topic = "bsh/"+dev["name"].replace(" ","_")+"/"
|
||||
return topic.replace("-","")
|
||||
|
||||
#update message for a single device
|
||||
def publishDevice(self,id):
|
||||
topicbase = self.getTopicBase(id)
|
||||
getRequest = self.session.get("https://"+self.IP_SHC+":8444/smarthome/devices/"+id["id"]+"/services", verify=False,
|
||||
cert = self.getCertificate(), headers = self.getURLHeaders())
|
||||
data = json.loads(getRequest.content)
|
||||
for id in data:
|
||||
if "state" in id:
|
||||
for s in self.states:
|
||||
if s in id["state"]:
|
||||
topic = topicbase+id["state"]["@type"]+"/"+s
|
||||
payload = id["state"][s]
|
||||
self.client.publish(topic,json.dumps(payload, indent=4, sort_keys=False),0,True)
|
||||
self.publishDebugMsg(" Publishing topic: "+ topic + " Payload: "+ json.dumps(payload, indent=4, sort_keys=False))
|
||||
|
||||
#publish the initial status messages
|
||||
def publishBSHStatus(self):
|
||||
for x in self.Devices:
|
||||
self.publishDevice(x)
|
||||
|
||||
#react to MQTT scenario requests:
|
||||
def onMqttMessage(self, client, userdata, message):
|
||||
#currently only react on trigger="ON"
|
||||
if (str(message.payload.decode("utf-8")) == "ON"):
|
||||
self.client.publish(message.topic,"OFF", 0,True)
|
||||
for s in self.Scenarios:
|
||||
topic = "bsh/scenarios/"+s["name"].replace(" ","_")+"/trigger"
|
||||
if (topic == message.topic):
|
||||
self.publishDebugMsg(" Scenario triggered: "+s["name"])
|
||||
url = self.baseurl + "/smarthome/scenarios/"+s["id"]+"/triggers"
|
||||
postRequest = requests.post(url, data="", headers = self.getURLHeaders(),
|
||||
verify = False, cert = self.getCertificate())
|
||||
data = json.loads(postRequest.text)[0]['result']
|
||||
if "errorCode" in data:
|
||||
self.publishDebugMsg("Error occured during Scenario Call:")
|
||||
self.publishDebugMsg(data["errorCode"])
|
||||
|
||||
#subscribe to message to trigger scenarios
|
||||
def subscribeToScenariosRequests(self):
|
||||
for s in self.Scenarios:
|
||||
topic = "bsh/scenarios/"+s["name"].replace(" ","_")+"/trigger"
|
||||
self.publishDebugMsg("Adding subscribe: "+topic)
|
||||
self.client.publish(topic,"OFF", 0,True)
|
||||
self.client.subscribe(topic,0)
|
||||
self.client.on_message = self.onMqttMessage
|
||||
|
||||
|
||||
#set up the system: login to MQTT + get all needed data from the BSH
|
||||
def __init__(self):
|
||||
self.client.connect(self.host_name)
|
||||
self.publishDebugMsg("Connecting to MQTT Server")
|
||||
self.publishDebugMsg("Setting up the Environment...")
|
||||
|
||||
self.publishDebugMsg("Getting Room information")
|
||||
self.Rooms = self.getRooms()
|
||||
self.publishDebugMsg(str(len(self.Rooms))+" rooms found:")
|
||||
for x in self.Rooms:
|
||||
self.publishDebugMsg(x["id"]+":"+x["name"])
|
||||
self.DicRooms.update({x["id"]:x})
|
||||
|
||||
self.publishDebugMsg("Getting Devices")
|
||||
self.Devices = self.getDevices()
|
||||
self.publishDebugMsg (str(len(self.Devices))+" Devices found:")
|
||||
for x in self.Devices:
|
||||
if "roomId" in x:
|
||||
self.publishDebugMsg(x["id"]+":"+x["name"]+":"+self.DicRooms[x["roomId"]]["name"])
|
||||
else:
|
||||
self.publishDebugMsg(x["id"]+":"+x["name"])
|
||||
|
||||
self.DicDevices.update({x["id"]:x})
|
||||
|
||||
self.publishDebugMsg("Getting Automation Rules")
|
||||
self.AutomationRules = self.getAutomationRules()
|
||||
self.publishDebugMsg(str(len(self.AutomationRules))+" Automation rules found:")
|
||||
for x in self.AutomationRules:
|
||||
self.publishDebugMsg(x["id"]+":"+x["name"])
|
||||
self.DicAutomationRules.update({x["id"]:x})
|
||||
|
||||
self.publishDebugMsg("Getting Senarios")
|
||||
self.Scenarios = self.getScenarios()
|
||||
self.publishDebugMsg (str(len(self.Scenarios))+" Scenarios found:")
|
||||
for x in self.Scenarios:
|
||||
self.publishDebugMsg(x["id"]+":"+x["name"])
|
||||
self.DicScenarios.update({x["id"]:x})
|
||||
|
||||
self.publishDebugMsg("Posting initial states to MQTT Server")
|
||||
self.publishBSHStatus()
|
||||
|
||||
self.publishDebugMsg("Subscribe to Service Requests")
|
||||
self.subscribeToScenariosRequests()
|
||||
|
||||
|
||||
def loop(self):
|
||||
self.publishDebugMsg("Subscribing to Bosch Smart Home System...")
|
||||
pollId = self.subscribe()
|
||||
self.publishDebugMsg(pollId)
|
||||
self.publishDebugMsg("Starting Polling...")
|
||||
#Restart Long Polling every 5 seconds
|
||||
while True:
|
||||
result = self.poll(pollId)
|
||||
if result != []:
|
||||
for e in result:
|
||||
if "deviceId" in e:
|
||||
if e["deviceId"] in self.DicDevices:
|
||||
self.publishDebugMsg("status change for: "+self.DicDevices[e["deviceId"]]["name"])
|
||||
self.publishDevice(self.DicDevices[e["deviceId"]])
|
||||
else:
|
||||
self.publishDebugMsg("Unknown message received:")
|
||||
self.publishDebugMsg('\n------------------------------------------------------ %d -\n' % len(result))
|
||||
self.publishDebugMsg(json.dumps(e, indent=4, sort_keys=False))
|
||||
self.client.loop_start()
|
||||
time.sleep(5)
|
||||
self.client.loop_stop()
|
||||
|
||||
|
||||
|
||||
BoschSmartHome = BSH()
|
||||
BoschSmartHome.loop()
|
||||
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
||||
#$ docker build -t my-python-app .
|
||||
#$ docker run -it --rm --name my-running-app my-python-app
|
||||
|
||||
FROM python:3
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD [ "python", "./BSHGateWay.py" ]
|
||||
16
example-cert.pem
Normal file
16
example-cert.pem
Normal file
@@ -0,0 +1,16 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICkTCCAXkCBFmSY3YwDQYJKoZIhvcNAQELBQAwDTELMAkGA1UEBhMCVVMwHhcN
|
||||
MTcwODE1MDI1OTAyWhcNMTgwODE1MDI1OTAyWjANMQswCQYDVQQGEwJVUzCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIZyQlYQUCkFq8KUMlRysRDkC5zH
|
||||
UZpZr4De4kVCQ10LMZeQLLsYtK/uPD71cNgzdoTNnDt1jHlDS8qJvq2c9yLXOO4l
|
||||
R+1vvz9GEUo5apVhWoJ2/rvmvQgVwGIa98o1s+Veh+EZlAKlmxuPuVK44ewpPxFD
|
||||
8fcEZzoCa4XiF14VrQrQAmC6/yWYk0QmQBCAx97UIE5XaLtZq8zhRTkhIHigMMQs
|
||||
5SLAmzCQTD1fxjbjNmCrWFmpJ6c7oodmwWvO6ciYS/IOemnSoViQxiPq+Y2iIGYy
|
||||
eP9JIF6eqljaMR9MQ9klwsBOlDTeUP7r5n7K6cD7wYjmK7nY8kxyYi6eR48CAwEA
|
||||
ATANBgkqhkiG9w0BAQsFAAOCAQEAPk9wfZSJBP31Tc5azEcRNUNxiFj473mGdxXp
|
||||
hsZAGrS/Pte0x+OGHhLDD2hkidIDhLrvbGN6OMTRtSouvuNYMSYbRuzfd8pe+0op
|
||||
dsuj/4+utK2MXE11C7L29ygYbPHIN/pn6jbSx3B8N+O/NsDLUuCOqzfp9EB8iQio
|
||||
6CplRrMb+cVj8MEmSD8qguAjUroozBunuxce72M82tyifRTByCx8xYwdRr8FGXfz
|
||||
1na4WzvnBh05hv0ywNzklgkoTKZk2Jw1G733PvNJ423IXBkFzDc2NIml++5St8xw
|
||||
Hu1IC1GIDzvaxuVMqF6ixLG8QGRXBKtpJgzFEY6qG/TkIeONBg==
|
||||
-----END CERTIFICATE-----
|
||||
28
example-key.pem
Normal file
28
example-key.pem
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCGckJWEFApBavC
|
||||
lDJUcrEQ5Aucx1GaWa+A3uJFQkNdCzGXkCy7GLSv7jw+9XDYM3aEzZw7dYx5Q0vK
|
||||
ib6tnPci1zjuJUftb78/RhFKOWqVYVqCdv675r0IFcBiGvfKNbPlXofhGZQCpZsb
|
||||
j7lSuOHsKT8RQ/H3BGc6AmuF4hdeFa0K0AJguv8lmJNEJkAQgMfe1CBOV2i7WavM
|
||||
4UU5ISB4oDDELOUiwJswkEw9X8Y24zZgq1hZqSenO6KHZsFrzunImEvyDnpp0qFY
|
||||
kMYj6vmNoiBmMnj/SSBenqpY2jEfTEPZJcLATpQ03lD+6+Z+yunA+8GI5iu52PJM
|
||||
cmIunkePAgMBAAECggEAZ7URWIPi4ZHfSQu5uwxxaz8NehUB7FcMGxNSZOxVPBtb
|
||||
WLc82eGX1zGkxUfckNk5rf1Qa0kkX5G6j/Qq4o72z6hG4ORfFFcjpfItehzKC4p6
|
||||
H7MckeLNo8Prj4GP7Cn6p46Ar/FkC5qlB+CYqqe0lc/HN1E6/zklS0j8mdyp+8cM
|
||||
aFx+unY/TDIrXMreIgSYr2Ys5XO2kN22pP+0Uf+OZic2+9EQOkIImvHpX6FEVw5j
|
||||
iXfGOYjwliiAtU0Ojso78ey5R/7SCRgpX2y3SCznquq0weVuqE0CrxecAlMgZRn8
|
||||
DklCNeaB0OytDKIfix5Q0yNKQThul98MPGgpDKC1oQKBgQC61WPO5XGhCEc2r8UB
|
||||
RkcSb792Tik/+JaOhZqwiZkx3jnBmU0HAb9VplOT1ciy4Kc4VilvwXNTbcUPx9KK
|
||||
2UUxPt1S8G4sfVBvgPSG0NWeFoCCMV+UxT7VpBfJTXUCygooy8w/GwLXeAhOAIpz
|
||||
F/Aj9Gz4F1YjsYG+Js7y7vxosQKBgQC4OAVfCDpNsJOLkY7csihbHhz+KohO7iOP
|
||||
giNF5YI6XKbaRARX6UeLnE2KkqF+CJWfO9REDcPT6kG/EHjsjYVGqHxUfm2B4DO7
|
||||
F/0JdE/5Smd8z7MxdDZDO7+TNMrtmpuQu57MGbk44mDAAXA954/M795PUVomxPx9
|
||||
6r3/einEPwKBgDcwV5ZDIoid6GNYEoqo1s+0YMsylW7HILoi7yncy3r2mPr+LMm4
|
||||
E2vagO+3g9yLDfpPQVg4vbdUQpTBwwiu24iLeFdKnFDaB4uYfSLhx2g2X2mV6hUJ
|
||||
GuGC4l/dWIYlZlDcuo2djf5V/6YC9OLAnHgSeKnkQtayVY/06MbMH5VRAoGBALEw
|
||||
URpDE7E+MeyAqOTmB6L8p+5ggpNIwrN5/OtyAXyZOXOfEH5uRv6l7H9o4iQTpbZv
|
||||
GZALnVvraimYcnc0+AgqbsvmfvX47Ej8ncnGMlYZlsiaDkV2/epVQcMZeEZp+0+O
|
||||
5wJxi5KHS3/i4k7ot4vq++1W1luMBUAn1XAx1JKJAoGBALN9hB2P0/36dyIUv2e9
|
||||
cGT2PO8I60aGNgCvQMADfDlfxTlquHAWJwu88IuzDLvG22sgserNMo3kyCRUCxLp
|
||||
cJZF+bSxKu2lVlbN9JJwBZSaz00l80xbYcjBIh9UhcXqKkeGbZhqF3nZ+C9VtFbD
|
||||
sIxIhyn924TNCEb3FzebpYKq
|
||||
-----END PRIVATE KEY-----
|
||||
17
linux-service/bsh-gateway.service
Normal file
17
linux-service/bsh-gateway.service
Normal file
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=BoschHomeAutomation 2 MQTT Gateway
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=idle
|
||||
Restart=always
|
||||
RestartSec=30
|
||||
StartLimitInterval=200
|
||||
StartLimitBurst=5
|
||||
|
||||
WorkingDirectory=/opt/bsh-gateway
|
||||
ExecStart=/opt/bsh-gateway/BSHGateWay.py
|
||||
ExecStop=/bin/sleep 1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
26
linux-service/easy_install.sh
Normal file
26
linux-service/easy_install.sh
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
mac=`cat /sys/class/net/$(ip route get 8.8.8.8 | sed -n 's/.* dev \([^ ]*\).*/\1/p')/address`
|
||||
arch=`uname -m`
|
||||
|
||||
### installing bsh gateway
|
||||
echo -e "\033[36m Installing BSH Gateway.\033[0m"
|
||||
|
||||
if [ -d "/opt/bsh-gateway" ]; then
|
||||
systemctl stop bsh-gateway.service
|
||||
cp BSHGateWay.py /opt/bsh-gateway/
|
||||
cp example-key.pem /opt/bsh-gateway/
|
||||
cp example-cert.pem /opt/bsh-gateway/
|
||||
else
|
||||
mkdir /opt/bsh-gateway
|
||||
cp BSHGateWay.py /opt/bsh-gateway/
|
||||
cp example-key.pem /opt/bsh-gateway/
|
||||
cp example-cert.pem /opt/bsh-gateway/
|
||||
fi
|
||||
|
||||
cp bsh-gateway.service /lib/systemd/system/
|
||||
chmod 644 /lib/systemd/system/bsh-gateway.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable bsh-gateway.service
|
||||
systemctl start bsh-gateway.service
|
||||
|
||||
echo -e "\033[32m Installation completed. BSH 2 MQTT Gateway is now up and running.\033[0m"
|
||||
18
linux-service/easy_uninstall.sh
Normal file
18
linux-service/easy_uninstall.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
cd /tmp
|
||||
|
||||
echo -e "\033[36m BSH GateWay Service.\033[0m"
|
||||
systemctl stop bsh-gateway.service
|
||||
|
||||
|
||||
### Uninstalling BSH GateWay
|
||||
echo -e "\033[36m Uninstalling BSH GateWay.\033[0m"
|
||||
|
||||
rm -rf /opt/bsh-gateway/
|
||||
|
||||
systemctl disable bsh-gateway.service
|
||||
rm /lib/systemd/system/bsh-gateway.service
|
||||
systemctl daemon-reload
|
||||
|
||||
|
||||
echo -e "\033[32m Uninstall complete!\033[0m"
|
||||
0
requirements.txt
Normal file
0
requirements.txt
Normal file
Reference in New Issue
Block a user