+117
@@ -0,0 +1,117 @@
|
|||||||
|
sudo: true
|
||||||
|
language: python
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- PROJECT=aqara-mqtt
|
||||||
|
- IMAGE_NAME=$DOCKER_USERNAME/$PROJECT
|
||||||
|
- VERSION=$(cat .semver)
|
||||||
|
- MAJOR=$(cut -d. -f1 .semver)
|
||||||
|
- MINOR=$(cut -d. -f2 .semver)
|
||||||
|
- PATCH=$(cut -d. -f3 .semver)
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- stage: build x64 image
|
||||||
|
before_script:
|
||||||
|
- ARCH=x64
|
||||||
|
|
||||||
|
script:
|
||||||
|
# build
|
||||||
|
- docker build -t $PROJECT -f Dockerfile-$ARCH .
|
||||||
|
|
||||||
|
# push image
|
||||||
|
- >
|
||||||
|
if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
|
||||||
|
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
|
||||||
|
|
||||||
|
#1.0.0-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$VERSION-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$VERSION-$ARCH
|
||||||
|
|
||||||
|
#1.0-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$MAJOR.$MINOR-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$MAJOR.$MINOR-$ARCH
|
||||||
|
|
||||||
|
#1-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$MAJOR-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$MAJOR-$ARCH
|
||||||
|
|
||||||
|
#latest by arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$ARCH
|
||||||
|
docker push $IMAGE_NAME:$ARCH
|
||||||
|
fi
|
||||||
|
|
||||||
|
- stage: build i386 image
|
||||||
|
before_script:
|
||||||
|
- ARCH=i386
|
||||||
|
|
||||||
|
script:
|
||||||
|
# build
|
||||||
|
- docker build -t $PROJECT -f Dockerfile-$ARCH .
|
||||||
|
|
||||||
|
# push image
|
||||||
|
- >
|
||||||
|
if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
|
||||||
|
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
|
||||||
|
|
||||||
|
#1.0.0-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$VERSION-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$VERSION-$ARCH
|
||||||
|
|
||||||
|
#1.0-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$MAJOR.$MINOR-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$MAJOR.$MINOR-$ARCH
|
||||||
|
|
||||||
|
#1-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$MAJOR-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$MAJOR-$ARCH
|
||||||
|
|
||||||
|
#latest by arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$ARCH
|
||||||
|
docker push $IMAGE_NAME:$ARCH
|
||||||
|
fi
|
||||||
|
|
||||||
|
- stage: build armhf image
|
||||||
|
before_script:
|
||||||
|
- ARCH=armhf
|
||||||
|
|
||||||
|
script:
|
||||||
|
# prepare qemu
|
||||||
|
- docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||||
|
# get qemu-arm-static binary
|
||||||
|
- >
|
||||||
|
mkdir tmp &&
|
||||||
|
pushd tmp &&
|
||||||
|
curl -L -o qemu-arm-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/v2.6.0/qemu-arm-static.tar.gz &&
|
||||||
|
tar xzf qemu-arm-static.tar.gz &&
|
||||||
|
popd
|
||||||
|
#copy it to container
|
||||||
|
- sed -i -e '2iCOPY tmp/qemu-arm-static /usr/bin/qemu-arm-static\' Dockerfile-$ARCH
|
||||||
|
|
||||||
|
# build
|
||||||
|
- docker build -t $PROJECT -f Dockerfile-$ARCH .
|
||||||
|
|
||||||
|
# push image
|
||||||
|
- >
|
||||||
|
if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
|
||||||
|
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
|
||||||
|
|
||||||
|
#1.0.0-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$VERSION-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$VERSION-$ARCH
|
||||||
|
|
||||||
|
#1.0-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$MAJOR.$MINOR-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$MAJOR.$MINOR-$ARCH
|
||||||
|
|
||||||
|
#1-arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$MAJOR-$ARCH
|
||||||
|
docker push $IMAGE_NAME:$MAJOR-$ARCH
|
||||||
|
|
||||||
|
#latest by arch
|
||||||
|
docker tag $PROJECT $IMAGE_NAME:$ARCH
|
||||||
|
docker push $IMAGE_NAME:$ARCH
|
||||||
|
fi
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
FROM arm32v7/python:slim
|
||||||
|
|
||||||
|
ENV LIBRARY_PATH=/lib:/usr/lib
|
||||||
|
|
||||||
|
ADD src/requirements.txt /
|
||||||
|
RUN apt-get update && apt-get install -y build-essential autoconf \
|
||||||
|
&& pip install --upgrade pip && pip install -r /requirements.txt \
|
||||||
|
&& apt-get remove -y build-essential autoconf \
|
||||||
|
&& apt-get autoremove -y \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY src /app
|
||||||
|
|
||||||
|
CMD ["python3", "-u", "/app/main.py"]
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
FROM alpine-python:latest
|
|
||||||
|
|
||||||
ENV LIBRARY_PATH=/lib:/usr/lib
|
|
||||||
|
|
||||||
ADD src/requirements.txt /
|
|
||||||
RUN pip install --upgrade pip && pip install -r /requirements.txt
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
COPY src /app
|
|
||||||
|
|
||||||
CMD ["python3", "-u", "/app/main.py"]
|
|
||||||
@@ -14,6 +14,12 @@ will turn on plug/heater and translate devices state from gateway:
|
|||||||
"home/plug/heater/status" on
|
"home/plug/heater/status" on
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
Docker image support following architectures (you must choose your architecture in docker-compose):
|
||||||
|
- armhf (raspberry pi 3, arm32v7)
|
||||||
|
- i386 (x86 pc)
|
||||||
|
- x64 (x64 pc)
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
Edit file config/config-sample.yaml and rename it to config/config.yaml
|
Edit file config/config-sample.yaml and rename it to config/config.yaml
|
||||||
|
|
||||||
@@ -21,7 +27,7 @@ Edit file config/config-sample.yaml and rename it to config/config.yaml
|
|||||||
Sample docker-compose.yaml file for user:
|
Sample docker-compose.yaml file for user:
|
||||||
```
|
```
|
||||||
aqara:
|
aqara:
|
||||||
image: monster1025/aqara-mqtt
|
image: monster1025/aqara-mqtt:1-armhf
|
||||||
container_name: aqara
|
container_name: aqara
|
||||||
volumes:
|
volumes:
|
||||||
- "./config:/app/config"
|
- "./config:/app/config"
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ mqtt:
|
|||||||
username: username
|
username: username
|
||||||
password: passw0rd
|
password: passw0rd
|
||||||
prefix: home
|
prefix: home
|
||||||
|
#send report as json
|
||||||
|
json: False
|
||||||
|
|
||||||
gateway:
|
gateway:
|
||||||
password: passw0rd
|
password: passw0rd
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
aqara:
|
aqara:
|
||||||
build: .
|
image: monster1025/aqara-mqtt:1-armhf
|
||||||
dockerfile: Dockerfile-rpi
|
|
||||||
container_name: aqara
|
container_name: aqara
|
||||||
volumes:
|
volumes:
|
||||||
- "./config:/app/config"
|
- "./config:/app/config"
|
||||||
|
|||||||
+19
-8
@@ -8,6 +8,7 @@ import json
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Mqtt:
|
class Mqtt:
|
||||||
|
event_based_sensors = ["switch", "cube"]
|
||||||
username = ""
|
username = ""
|
||||||
password = ""
|
password = ""
|
||||||
server = "localhost"
|
server = "localhost"
|
||||||
@@ -38,6 +39,7 @@ class Mqtt:
|
|||||||
self.server = mqttConfig.get("server", "localhost")
|
self.server = mqttConfig.get("server", "localhost")
|
||||||
self.port = mqttConfig.get("port", 1883)
|
self.port = mqttConfig.get("port", 1883)
|
||||||
self.prefix = mqttConfig.get("prefix", "home")
|
self.prefix = mqttConfig.get("prefix", "home")
|
||||||
|
self.json = mqttConfig.get("json", False)
|
||||||
self._queue = Queue()
|
self._queue = Queue()
|
||||||
self._threads = []
|
self._threads = []
|
||||||
|
|
||||||
@@ -72,8 +74,6 @@ class Mqtt:
|
|||||||
model = sidprops.get("model",model)
|
model = sidprops.get("model",model)
|
||||||
sid = sidprops.get("name",sid)
|
sid = sidprops.get("name",sid)
|
||||||
|
|
||||||
# _LOGGER.info("data is " + format(data))
|
|
||||||
PATH_FMT = self.prefix + "/{model}/{sid}/{prop}"
|
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
# fix for latest motion value
|
# fix for latest motion value
|
||||||
if (model == "motion" and key == "no_motion"):
|
if (model == "motion" and key == "no_motion"):
|
||||||
@@ -82,18 +82,29 @@ class Mqtt:
|
|||||||
if (model == "magnet" and key == "no_close"):
|
if (model == "magnet" and key == "no_close"):
|
||||||
key="status"
|
key="status"
|
||||||
value="open"
|
value="open"
|
||||||
|
|
||||||
# do not retain event-based sensors (like switches and cubes).
|
# do not retain event-based sensors (like switches and cubes).
|
||||||
if (model in ["switch", "cube"]):
|
if (model in self.event_based_sensors):
|
||||||
retain = False
|
retain = False
|
||||||
|
|
||||||
# fix for rgb format
|
# fix for rgb format
|
||||||
if (key == "rgb" and self._is_int(value)):
|
if (key == "rgb" and self._is_int(value)):
|
||||||
value = self._color_xiaomi_to_rgb(value)
|
value = self._color_xiaomi_to_rgb(value)
|
||||||
|
|
||||||
topic = PATH_FMT.format(model=model, sid=sid, prop=key)
|
if self.json == True:
|
||||||
_LOGGER.info("Publishing message to topic " + topic + ": " + str(value) + ".")
|
PATH_FMT = self.prefix + "/{model}/{sid}/json"
|
||||||
self._client.publish(topic, payload=value, qos=0, retain=retain)
|
topic = PATH_FMT.format(model=model, sid=sid)
|
||||||
|
values = {}
|
||||||
|
values['sid'] = sid
|
||||||
|
for key, value in data.items():
|
||||||
|
values[key] = value
|
||||||
|
jsondata = json.dumps(values)
|
||||||
|
_LOGGER.info("Publishing message to topic " + topic + ": " + str(jsondata) + ".")
|
||||||
|
self._client.publish(topic, payload=jsondata, qos=0, retain=retain)
|
||||||
|
else:
|
||||||
|
for key, value in data.items():
|
||||||
|
PATH_FMT = self.prefix + "/{model}/{sid}/{prop}"
|
||||||
|
topic = PATH_FMT.format(model=model, sid=sid, prop=key)
|
||||||
|
_LOGGER.info("Publishing message to topic " + topic + ": " + str(value) + ".")
|
||||||
|
self._client.publish(topic, payload=value, qos=0, retain=retain)
|
||||||
|
|
||||||
def _mqtt_on_connect(self, client, userdata, rc, unk):
|
def _mqtt_on_connect(self, client, userdata, rc, unk):
|
||||||
_LOGGER.info("Connected to mqtt server.")
|
_LOGGER.info("Connected to mqtt server.")
|
||||||
|
|||||||
Reference in New Issue
Block a user