diff --git a/.github/workflows/github-push-docker.yml b/.github/workflows/github-push-docker.yml index 552f4dd..2b65b1f 100644 --- a/.github/workflows/github-push-docker.yml +++ b/.github/workflows/github-push-docker.yml @@ -11,6 +11,13 @@ env: jobs: build-and-push-image: runs-on: ubuntu-latest + strategy: + matrix: + image: + - suffix: '' + start_file: start_telegram.py + - suffix: '-meshcore-ha' + start_file: start_meshcore_ha.py permissions: contents: read packages: write @@ -30,12 +37,14 @@ jobs: id: meta uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.image.suffix }} - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: context: . + build-args: | + START_FILE=${{ matrix.image.start_file }} push: true tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index f8fe452..d86139e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,9 @@ -FROM python:3.11.2-alpine3.17 +FROM python:3.12-alpine LABEL Maintainer="serega404" WORKDIR /app +ARG START_FILE=start_telegram.py COPY requirements.txt requirements.txt RUN pip3 install -r requirements.txt @@ -11,7 +12,7 @@ RUN pip3 install -r requirements.txt COPY crontab /tmp/crontab RUN cat /tmp/crontab > /etc/crontabs/root -COPY start_telegram.py start_telegram.py +COPY ${START_FILE} start.py COPY parser.py parser.py # run crond as main process of container diff --git a/README.md b/README.md index 35789cc..c7bec55 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![MIT License](https://img.shields.io/github/license/serega404/VodokanalBot)](https://github.com/serega404/VodokanalBot) -## Запуск в Docker +## Запуск TG интеграции в Docker ``` Docker docker volume create vodokanal_bot_data @@ -15,7 +15,7 @@ docker run -d --name VodokanalBot \ ghcr.io/serega404/vodokanalbot:main ``` -## Запуск в Docker Compose +### Запуск в Docker Compose Укажи `TELEGRAM_TOKEN` и `TELEGRAM_CHANNEL` в [`docker-compose.yml`](./docker-compose.yml), затем запусти: @@ -23,6 +23,33 @@ docker run -d --name VodokanalBot \ docker compose up -d --build ``` +## Запуск с MeshCore + Home Assistant + +Вариант для MeshCore отправляет новые сообщения в webhook Home Assistant, а Home Assistant пересылает их в канал MeshCore. + +1. Добавь в Home Assistant автоматизацию [`Webhook to MeshCore channel`](https://github.com/serega404/HA-MeshCore#webhook-to-meshcore-channel). +2. Замени `CHANGE_ME_RANDOM_WEBHOOK_ID` в автоматизации на случайную строку. + +``` Docker +docker volume create vodokanal_bot_data +docker run -d --name VodokanalBot \ + --restart=always \ + -v vodokanal_bot_data:/app/data \ + -e TZ='Europe/Moscow' \ + -e HOME_ASSISTANT_WEBHOOK_ID='CHANGE_ME_RANDOM_WEBHOOK_ID' \ + -e HOME_ASSISTANT_URL='http://homeassistant.local:8123' \ + -e HOME_ASSISTANT_WEBHOOK_CHANNEL='0' \ + ghcr.io/serega404/vodokanalbot-meshcore-ha:main +``` + +### Запуск в Docker Compose + +Укажи `HOME_ASSISTANT_WEBHOOK_ID` и `HOME_ASSISTANT_WEBHOOK_CHANNEL` в [`docker-compose.ha.yml`](./docker-compose.ha.yml), затем запусти: + +``` Docker +docker compose up -d --build -f docker-compose.ha.yml +``` + ## Интеграции Общая логика парсинга, работы с `data/db.json` и поиска новых сообщений вынесена в [`parser.py`](./parser.py). diff --git a/crontab b/crontab index 4383999..aa9778d 100644 --- a/crontab +++ b/crontab @@ -1,2 +1,2 @@ -@reboot cd /app && python3 /app/start_telegram.py -*/10 * * * * cd /app && python3 /app/start_telegram.py +@reboot cd /app && python3 /app/start.py +*/10 * * * * cd /app && python3 /app/start.py diff --git a/docker-compose.ha.yml b/docker-compose.ha.yml new file mode 100644 index 0000000..9834d66 --- /dev/null +++ b/docker-compose.ha.yml @@ -0,0 +1,22 @@ +services: + vodokanalbot-ha: + image: ghcr.io/serega404/vodokanalbot-meshcore-ha:main + build: + context: . + args: + START_FILE: start_meshcore_ha.py + container_name: VodokanalBotMeshCoreHA + restart: always + environment: + TZ: Europe/Moscow + HOME_ASSISTANT_URL: https://your-home-assistant-url + HOME_ASSISTANT_WEBHOOK_ID: CHANGE_ME_RANDOM_WEBHOOK_ID + HOME_ASSISTANT_WEBHOOK_CHANNEL: "0" + # VODOKANAL_URL: http://www.tgnvoda.ru/avarii.php + # PROXY_URL: socks5h://user:password@proxy-host:1080 + # PROXY_URL: http://user:password@proxy-host:3128 + volumes: + - vodokanal_bot_data:/app/data + +volumes: + vodokanal_bot_data: diff --git a/docker-compose.yml b/docker-compose.yml index 630da02..8a4ace5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,17 @@ services: vodokanalbot: image: ghcr.io/serega404/vodokanalbot:main + build: + context: . + args: + START_FILE: start_telegram.py container_name: VodokanalBot restart: always environment: TZ: Europe/Moscow TELEGRAM_TOKEN: TOKEN TELEGRAM_CHANNEL: CHAT_ID + # VODOKANAL_URL: http://www.tgnvoda.ru/avarii.php # PROXY_URL: socks5h://user:password@proxy-host:1080 # PROXY_URL: http://user:password@proxy-host:3128 volumes: diff --git a/parser.py b/parser.py index 86a25ae..0cf7a21 100644 --- a/parser.py +++ b/parser.py @@ -8,7 +8,7 @@ from bs4 import BeautifulSoup DEFAULT_DB_PATH = "data/db.json" - +DEFAULT_VODOKANAL_URL = "http://www.tgnvoda.ru/avarii.php" @dataclass(frozen=True) class Post: @@ -31,7 +31,6 @@ def create_session(proxy_url=""): return session - def load_database(path=DEFAULT_DB_PATH): if not os.path.isfile(path): print("Database not loaded") @@ -89,9 +88,9 @@ def get_new_posts(posts, database): return [post for post in posts if post.key not in database_keys] -def publish_new_posts(send_message, session, url, db_path=DEFAULT_DB_PATH): +def publish_new_posts(send_message, session, db_path=DEFAULT_DB_PATH): database = load_database(db_path) - posts = fetch_posts(session, url) + posts = fetch_posts(session, DEFAULT_VODOKANAL_URL) if not posts: print("No posts") diff --git a/start_meshcore_ha.py b/start_meshcore_ha.py new file mode 100644 index 0000000..9bce9c3 --- /dev/null +++ b/start_meshcore_ha.py @@ -0,0 +1,56 @@ +import os + +from parser import create_session, publish_new_posts + + +PROXY_URL = os.environ.get('PROXY_URL', '') +HOME_ASSISTANT_URL = os.environ.get('HOME_ASSISTANT_URL', '') +HOME_ASSISTANT_WEBHOOK_ID = os.environ.get('HOME_ASSISTANT_WEBHOOK_ID', '') +HOME_ASSISTANT_WEBHOOK_CHANNEL = os.environ.get('HOME_ASSISTANT_WEBHOOK_CHANNEL', '0') + + +def create_webhook_url(): + return ( + HOME_ASSISTANT_URL.rstrip('/') + + "/api/webhook/" + + HOME_ASSISTANT_WEBHOOK_ID + ) + + +def send_webhook_message(session, message): + req = session.get( + create_webhook_url(), + params={ + 'channel': HOME_ASSISTANT_WEBHOOK_CHANNEL, + 'message': message, + }, + ) + if not 200 <= req.status_code < 300: + print("Home Assistant webhook request error: " + str(req.status_code)) + exit() + else: + print("Home Assistant webhook message sent") + + +def main(): + if HOME_ASSISTANT_URL == '': + print("Home Assistant URL is not set") + exit() + + if HOME_ASSISTANT_WEBHOOK_ID == '': + print("Home Assistant webhook id is not set") + exit() + + session = create_session(PROXY_URL) + try: + publish_new_posts( + send_message=lambda message: send_webhook_message(session, message), + session=session, + ) + except RuntimeError as error: + print(error) + exit() + + +if __name__ == "__main__": + main() diff --git a/start_telegram.py b/start_telegram.py index 1a3b6e0..42f88a3 100644 --- a/start_telegram.py +++ b/start_telegram.py @@ -3,7 +3,6 @@ import os from parser import create_session, publish_new_posts -URL = os.environ.get('VODOKANAL_URL', 'http://www.tgnvoda.ru/avarii.php') SEND_SILENT = os.environ.get('SEND_SILENT', False) TELEGRAM_TOKEN = os.environ.get('TELEGRAM_TOKEN', '') TELEGRAM_CHANNEL = os.environ.get('TELEGRAM_CHANNEL', '') @@ -40,7 +39,6 @@ def main(): publish_new_posts( send_message=lambda message: send_telegram_message(session, message), session=session, - url=URL, ) except RuntimeError as error: print(error)