Skip to content

Commit

Permalink
Merge pull request #1 from ysakashita/init
Browse files Browse the repository at this point in the history
Init
  • Loading branch information
ysakashita authored Feb 26, 2024
2 parents 372915a + 23c35f7 commit 462e5ba
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,6 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
manifests/.token
manifests/.secret.yaml
test/*
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @ysakashita
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM python:3.9.18

COPY requirements.txt /
RUN pip install --upgrade pip
RUN pip install -r /requirements.txt

CMD ["python3"]
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
IMG := ysakashita/python-merossiot
TAG := 3.9.18-0.4.6.2

.PHONY: build-image
build-image:
docker buildx build --platform linux/arm64 -t $(IMG):$(TAG) --load .

.PHONY: push-image
push-image: build-image
docker push $(IMG):$(TAG)
87 changes: 85 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,85 @@
# haro
haro bot
# haro とは

ハロ(haro)は、Slack用のBotです。
Slackに通知されたAlert Managerからのアラートメッセージを受け、スマート電源タップ(Meross)の電源を制御します。

これにより、ユニコーンガンダムのNT-Dを発動させ光らせること等ができます。

デモ動画は[こちら](https://youtu.be/0-yCTHrpOm0)を参照ください。

# セットアップ方法

## コマンドで起動する場合

1. 環境変数を設定

```
$ export SLACK_APP_TOKEN=<Slack Appのトークン (e.g., xapp-x-xxx)>
$ export SLACK_BOT_TOKEN=<Slack Botのトークン (e.g., xoxb-xxxxx)>
$ export ALERTMANAGER_ID=<Slackでの AlertManagerのBot ID (e.g., B03DZ3JPES2)>
$ export MEROSS_EMAIL=<Merossのユーザ登録しているメールアドレス>
$ export MEROSS_PASSWORD=<Merossのパスワード>
$ export MEROSS_DEVICE_TYPE=<Merossのデバイスタイプ (e.g., mss425f)>
$ export MEROSS_DEVICE_NAME=<Merossのデバイス名 (e.g., tap1)>
$ export MEROSS_DEVICE_CHANNEL=<Meross上のコンセント番号 (e.g., 3)>
```

2. Pythonのパッケージをインストール

```
$ pip install -r requirements.txt
```

3. haro.pyを実行

```
$ cd manifests
$ python ./haro.py
```

## Kubernetes上で起動する場合

1. ネームスペースを作成

```
$ kubectl create ns haro
```

2. secret.yaml を作成

```YAML
apiVersion: v1
kind: Secret
metadata:
name: haro
namespace: haro
type: Opaque
data:
SLACK_APP_TOKEN: <Slack Appのトークン (e.g., xapp-x-xxx)>
SLACK_BOT_TOKEN: <Slack Botのトークン (e.g., xoxb-xxxxx)>
ALERTMANAGER_ID: <Slackでの AlertManagerのBot ID (e.g., B03DZ3JPES2)>
MEROSS_EMAIL: <Merossのユーザ登録しているメールアドレス>
MEROSS_PASSWORD: <Merossのパスワード>
MEROSS_DEVICE_TYPE: <Merossのデバイスタイプ (e.g., mss425f)>
MEROSS_DEVICE_NAME: <Merossのデバイス名 (e.g., tap1)>
MEROSS_DEVICE_CHANNEL: <Meross上のコンセント番号 (e.g., 3)>
```
:memo: 各値はbase64でエンコードした値を設定してください。
(e.g., Base64へのエンコードの実行例)
```
$ echo -n "xapp-x-xxx" |base64
```

3. secret.yamlのデプロイ

```
$ kubectl apply -f secret.yaml
```

4. haroのデプロイ

```
$ kubectl apply -k manifests/
```
74 changes: 74 additions & 0 deletions manifests/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: haro
namespace: haro
spec:
replicas: 1
selector:
matchLabels:
app: haro
template:
metadata:
labels:
app: haro
spec:
containers:
- name: haro
imagePullPolicy: Always
image: ysakashita/python-merossiot:3.9.18-0.4.6.2
resources:
limits:
memory: "128Mi"
cpu: "500m"
env:
- name: SLACK_APP_TOKEN
valueFrom:
secretKeyRef:
name: haro
key: SLACK_APP_TOKEN
- name: SLACK_BOT_TOKEN
valueFrom:
secretKeyRef:
name: haro
key: SLACK_BOT_TOKEN
- name: ALERTMANAGER_ID
valueFrom:
secretKeyRef:
name: haro
key: ALERTMANAGER_ID
- name: MEROSS_EMAIL
valueFrom:
secretKeyRef:
name: haro
key: MEROSS_EMAIL
- name: MEROSS_PASSWORD
valueFrom:
secretKeyRef:
name: haro
key: MEROSS_PASSWORD
- name: MEROSS_DEVICE_TYPE
valueFrom:
secretKeyRef:
name: haro
key: MEROSS_DEVICE_TYPE
- name: MEROSS_DEVICE_NAME
valueFrom:
secretKeyRef:
name: haro
key: MEROSS_DEVICE_NAME
- name: MEROSS_DEVICE_CHANNEL
valueFrom:
secretKeyRef:
name: haro
key: MEROSS_DEVICE_CHANNEL
command:
- "python"
- "/bot/haro.py"
volumeMounts:
- mountPath: /bot
name: script
volumes:
- name: script
configMap:
name: haro
90 changes: 90 additions & 0 deletions manifests/haro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import asyncio
import os

from meross_iot.http_api import MerossHttpClient
from meross_iot.manager import MerossManager

import logging
from slack_sdk import WebClient
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

logging.basicConfig(level=logging.info, format='%(asctime)s %(message)s')

MEROSS_EMAIL = os.getenv('MEROSS_EMAIL')
MEROSS_PASSWORD = os.getenv('MEROSS_PASSWORD')
MEROSS_DEVICE_TYPE = os.getenv('MEROSS_DEVICE_TYPE')
MEROSS_DEVICE_NAME = os.getenv('MEROSS_DEVICE_NAME')
MEROSS_DEVICE_CHANNEL = os.getenv('MEROSS_DEVICE_CHANNEL')

ALERTMANAGERID = os.getenv("ALERTMANAGER_ID")

SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")
SLACK_APP_TOKEN = os.getenv("SLACK_APP_TOKEN")

app = App(token=SLACK_BOT_TOKEN)
loop = asyncio.get_event_loop()

async def _ntd(status):
http_api_client = await MerossHttpClient.async_from_user_password(api_base_url='https://iotx-ap.meross.com',
email=MEROSS_EMAIL,
password=MEROSS_PASSWORD)
manager = MerossManager(http_client=http_api_client)
await manager.async_init()
await manager.async_device_discovery()
device =manager.find_devices(device_type=MEROSS_DEVICE_TYPE, device_name=MEROSS_DEVICE_NAME)

if len(device) == 1:
if status :
await device[0].async_turn_on(channel=MEROSS_DEVICE_CHANNEL)
else:
await device[0].async_turn_off(channel=MEROSS_DEVICE_CHANNEL)
else:
print("Not found divice")

manager.close()
await http_api_client.async_logout()

def ntd(status):
loop.run_until_complete(_ntd(status))

# Event API
@app.event("message")
def handle_alert(event, say):
logging.debug("Calling handle_alert()")
logging.info("handle_alert(event): %s", str(event))

thread_ts = event.get("thread_ts") or None
bot_id = event.get("bot_id") or None
channel = event["channel"]

if thread_ts != None:
logging.info("Ignore the message because it is tme message in a thread")
return

if bot_id is None:
logging.info("Ignore the message because it is not a Bot")
return

if bot_id != ALERTMANAGERID:
logging.info("Ignore the message because it is not an Alert message")
return

res = app.client.conversations_replies(channel=channel, ts=event["ts"])
thread = res["messages"][0]["ts"]

for attachment in event["attachments"]:
title = attachment["title"]
if title.startswith('[FIRING'):
say(text="NT-D発動", thread_ts=thread, channel=channel)
ntd(1)
elif title.startswith('[RESOLVED'):
say(text="NT-D停止", thread_ts=thread, channel=channel)
ntd(0)

if __name__ == '__main__':
# Start slack bot
handler = SocketModeHandler(app, SLACK_APP_TOKEN)
handler.start()

loop.close()
9 changes: 9 additions & 0 deletions manifests/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: haro
configMapGenerator:
- name: haro
files:
- haro.py
resources:
- deployment.yaml
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
slack_bolt==1.8
meross_iot==0.4.6.2
asyncio==3.4.3

0 comments on commit 462e5ba

Please sign in to comment.