diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 1b85129..35d5d8c 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -5,7 +5,7 @@ on: inputs: username: description: 'version of this branch' - default: 'v1.6.2' + default: 'v1.6.3' required: true type: string paths: @@ -32,13 +32,29 @@ jobs: - name: Build and push Docker image run: | - PLATFORMS=linux/arm64,linux/amd64 - DOCKER_IMAGE=arcw/sgcc_electricity - docker buildx build --build-arg VERSION=${{ inputs.username }} --platform $PLATFORMS -t $DOCKER_IMAGE:latest -t $DOCKER_IMAGE:${{ inputs.username }} --file Dockerfile-for-github-action --push . + ARCH_TAGS="arm64 amd64" + DOCKER_PATH=arcw + DOCKER_IMAGE=sgcc_electricity + for ARCH in $ARCH_TAGS; do + if [ "$ARCH" == "arm64" ]; then + TAG_ARCH="aarch64" + else + TAG_ARCH=$ARCH + fi + docker buildx build --build-arg VERSION=${{ inputs.username }} --platform linux/$ARCH -t $DOCKER_PATH/$TAG_ARCH-$DOCKER_IMAGE:latest -t $DOCKER_PATH/$DOCKER_IMAGE:latest -t $DOCKER_PATH/$DOCKER_IMAGE:${{ inputs.username }} --file Dockerfile-for-github-action --push . + done - name: Log into Aliyun hub registry and push Docker image run: | echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.ALIYUN_USERNAME }} --password-stdin registry.cn-hangzhou.aliyuncs.com - PLATFORMS=linux/arm64,linux/amd64 - DOCKER_IMAGE=registry.cn-hangzhou.aliyuncs.com/arcw/sgcc_electricity - docker buildx build --build-arg VERSION=${{ inputs.username }} --platform $PLATFORMS -t $DOCKER_IMAGE:latest -t $DOCKER_IMAGE:${{ inputs.username }} --file Dockerfile-for-github-action --push . \ No newline at end of file + ARCH_TAGS="arm64 amd64" + DOCKER_PATH=registry.cn-hangzhou.aliyuncs.com/arcw + DOCKER_IMAGE=sgcc_electricity + for ARCH in $ARCH_TAGS; do + if [ "$ARCH" == "arm64" ]; then + TAG_ARCH="aarch64" + else + TAG_ARCH=$ARCH + fi + docker buildx build --build-arg VERSION=${{ inputs.username }} --platform linux/$ARCH -t $DOCKER_PATH/$TAG_ARCH-$DOCKER_IMAGE:latest -t $DOCKER_PATH/$DOCKER_IMAGE:latest -t $DOCKER_PATH/$DOCKER_IMAGE:${{ inputs.username }} --file Dockerfile-for-github-action --push . + done \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 11f6e0c..71b9ae0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,9 @@ -FROM arcw/sgcc_electricity:latest +ARG BUILD_FROM +FROM $BUILD_FROM -COPY run.sh /run.sh -RUN chmod +x /run.sh +ENV SET_CONTAINER_TIMEZONE true +ENV CONTAINER_TIMEZONE Asia/Shanghai -ENV LANG C.UTF-8 -ENTRYPOINT ["/bin/bash", "/run.sh"] +WORKDIR /app + +CMD ["python3", "main.py"] diff --git a/build.yaml b/build.yaml index 1e8fe6d..3565058 100644 --- a/build.yaml +++ b/build.yaml @@ -1,7 +1,6 @@ build_from: - aarch64: registry.cn-hangzhou.aliyuncs.com/arcw/sgcc_electricity:latest - amd64: registry.cn-hangzhou.aliyuncs.com/arcw/sgcc_electricity:latest -labels: - org.opencontainers.image.title: "SGCC Electricity Add-on" - org.opencontainers.image.description: "State Grid Electric Data" - org.opencontainers.image.source: "https://github.com/ARC-MX/sgcc_electricity_new" + aarch64: registry.cn-hangzhou.aliyuncs.com/arcw/aarch64-sgcc_electricity:latest + amd64: registry.cn-hangzhou.aliyuncs.com/arcw/amd64-sgcc_electricity:latest +codenotary: + base_image: ARC-MX@github.com + signer: ARC-MX@github.com diff --git a/config.yaml b/config.yaml index dbcdf0b..6c30c8a 100644 --- a/config.yaml +++ b/config.yaml @@ -1,7 +1,7 @@ -name: "SGCC Electricity New" -version: "latest" -slug: "sgcc_electricity_new" -description: "获取国网电费数据的插件(新版)" +name: "SGCC Electricity" +version: "v0.1.0" +slug: "sgcc_electricity" +description: "获取国网电费数据的插件" url: "https://github.com/ARC-MX/sgcc_electricity_new" arch: - aarch64 @@ -10,12 +10,13 @@ host_network: true startup: application boot: auto init: false -#image: "{arch}-sgcc_electricity_new" +# image: "registry.cn-hangzhou.aliyuncs.com/arcw/{arch}-addon-sgcc_electricity" map: - config:rw options: phone: "" - password: "" + password: "" + ignore_user_id: "xxxx,xxxx" enable_database_storage: false db_name: "homeassistant.db" hass_url: "http://homeassistant.local:8123/" @@ -29,11 +30,11 @@ options: data_retention_days: 7 recharge_notify: false balance: 5.0 - pushplus_token: "" + pushplus_token: "xxxx,xxxx" schema: phone: str password: password - IGNORE_USER_ID: "str?" + ignore_user_id: str enable_database_storage: bool db_name: str hass_url: str @@ -47,11 +48,11 @@ schema: data_retention_days: int recharge_notify: bool balance: float - pushplus_token: "str?" + pushplus_token: str environment: PHONE_NUMBER: "${phone}" PASSWORD: "${password}" - IGNORE_USER_ID: "${IGNORE_USER_ID}" + IGNORE_USER_ID: "${ignore_user_id}" ENABLE_DATABASE_STORAGE: "${enable_database_storage}" DB_NAME: "${db_name}" HASS_URL: "${hass_url}" @@ -63,6 +64,6 @@ environment: RETRY_WAIT_TIME_OFFSET_UNIT: "${retry_wait_time_offset_unit}" LOG_LEVE: "${log_level}" DATA_RETENTION_DAYS: "${data_retention_days}" - RECHARGE_NOTIFY: "${IGNORE_USER_ID}" + RECHARGE_NOTIFY: "${recharge_notify}" BALANCE: "${balance}" PUSHPLUS_TOKEN: "${pushplus_token}" \ No newline at end of file diff --git a/repository.yaml b/repository.yaml index cba2bde..800cb90 100644 --- a/repository.yaml +++ b/repository.yaml @@ -1,3 +1,3 @@ -name: sgcc_electricity_new add-on repository +name: sgcc_electricity add-on repository url: 'https://github.com/ARC-MX/sgcc_electricity_new' -maintainer: sgcc_electricity_new +maintainer: sgcc_electricity diff --git a/requirements.txt b/requirements.txt index b7eb999..a91ef66 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,5 @@ Pillow==10.1.0 undetected_chromedriver==3.5.4 onnxruntime==1.18.1 numpy==1.26.2 -python-dotenv -python-dateutil \ No newline at end of file +# python-dotenv +# python-dateutil \ No newline at end of file diff --git a/run.sh b/run.sh deleted file mode 100644 index df2cbb4..0000000 --- a/run.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash -# Read configuration from options.json -CONFIG_PATH="/data/options.json" -if [ ! -f "$CONFIG_PATH" ]; then - echo "Error: Configuration file not found $CONFIG_PATH" - exit 1 -fi -# Use jq to read config and set environment variables -export PHONE_NUMBER=$(jq -r '.phone // empty' "$CONFIG_PATH") -export PASSWORD=$(jq -r '.password // empty' "$CONFIG_PATH") -export IGNORE_USER_ID=$(jq -r '.IGNORE_USER_ID // empty' "$CONFIG_PATH") -export ENABLE_DATABASE_STORAGE=$(jq -r '.enable_database_storage // "false"' "$CONFIG_PATH") -export DB_NAME=$(jq -r '.db_name // "homeassistant.db"' "$CONFIG_PATH") -export HASS_URL=$(jq -r '.hass_url // empty' "$CONFIG_PATH") -export HASS_TOKEN=$(jq -r '.hass_token // empty' "$CONFIG_PATH") -export JOB_START_TIME=$(jq -r '.job_start_time // "00:00"' "$CONFIG_PATH") -export DRIVER_IMPLICITLY_WAIT_TIME=$(jq -r '.driver_implicitly_wait_time // "10"' "$CONFIG_PATH") -export RETRY_TIMES_LIMIT=$(jq -r '.retry_times_limit // "3"' "$CONFIG_PATH") -export LOGIN_EXPECTED_TIME=$(jq -r '.login_expected_time // "60"' "$CONFIG_PATH") -export RETRY_WAIT_TIME_OFFSET_UNIT=$(jq -r '.retry_wait_time_offset_unit // "5"' "$CONFIG_PATH") -export LOG_LEVEL=$(jq -r '.log_level // "INFO"' "$CONFIG_PATH") -export DATA_RETENTION_DAYS=$(jq -r '.data_retention_days // "30"' "$CONFIG_PATH") -export RECHARGE_NOTIFY=$(jq -r '.recharge_notify // "false"' "$CONFIG_PATH") -export BALANCE=$(jq -r '.balance // "50"' "$CONFIG_PATH") -export PUSHPLUS_TOKEN=$(jq -r '.pushplus_token // empty' "$CONFIG_PATH") -# Check required environment variables -if [ -z "$PHONE_NUMBER" ]; then - echo "Error: Phone number not set" - exit 1 -fi -if [ -z "$PASSWORD" ]; then - echo "Error: Password not set" - exit 1 -fi -if [ -z "$HASS_URL" ]; then - echo "Error: Home Assistant URL not set" - exit 1 -fi -if [ -z "$HASS_TOKEN" ]; then - echo "Error: Home Assistant Token not set" - exit 1 -fi -# Output environment variables log -echo "Environment variables setup completed:" -echo "Phone Number: ${PHONE_NUMBER:-Not Set}" -echo "Home Assistant URL: ${HASS_URL:-Not Set}" -echo "Job Start Time: ${JOB_START_TIME:-Not Set}" -echo "Log Level: ${LOG_LEVEL:-Not Set}" -echo "Data Retention Days: ${DATA_RETENTION_DAYS:-Not Set}" -# Start main program -python3 /app/main.py \ No newline at end of file diff --git a/scripts/data_fetcher.py b/scripts/data_fetcher.py index 5c2c012..906d106 100644 --- a/scripts/data_fetcher.py +++ b/scripts/data_fetcher.py @@ -1,4 +1,3 @@ -from ast import Try import logging import os import re @@ -7,9 +6,6 @@ import random import base64 -import json -import requests -import dotenv import sqlite3 import undetected_chromedriver as uc from datetime import datetime @@ -86,7 +82,8 @@ def get_transparency_location(image): class DataFetcher: def __init__(self, username: str, password: str): - dotenv.load_dotenv() + if 'PYTHON_IN_DOCKER' not in os.environ: + dotenv.load_dotenv(verbose=True) self._username = username self._password = password self.onnx = ONNX("./captcha.onnx") @@ -142,16 +139,6 @@ def _sliding_track(self, driver, distance):# 机器模拟人工滑动轨迹 # time.sleep(0.2) ActionChains(driver).release().perform() - def base64_api(self, b64, typeid=33): - data = {"username": self._tujian_uname, "password": self._tujian_passwd, "typeid": typeid, "image": b64} - result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text) - if result['success']: - return result["data"]["result"] - else: - #!!!!!!!注意:返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别 - return result["message"] - return "" - def connect_user_db(self, user_id): """创建数据库集合,db_name = electricity_daily_usage_{user_id} :param user_id: 用户ID""" @@ -269,7 +256,7 @@ def _login(self, driver, phone_code = False): self._click_button(driver, By.XPATH, '//*[@id="login_box"]/div[1]/div[1]/div[2]/span') #get canvas image background_JS = 'return document.getElementById("slideVerify").childNodes[0].toDataURL("image/png");' - targe_JS = 'return document.getElementsByClassName("slide-verify-block")[0].toDataURL("image/png");' + # targe_JS = 'return document.getElementsByClassName("slide-verify-block")[0].toDataURL("image/png");' # get base64 image data im_info = driver.execute_script(background_JS) background = im_info.split(',')[1] @@ -317,11 +304,13 @@ def fetch(self): logging.info("login successed !") else: logging.info("login unsuccessed !") + raise Exception("login unsuccessed") else: if self._login(driver): logging.info("login successed !") else: logging.info("login unsuccessed !") + raise Exception("login unsuccessed") except Exception as e: logging.error( f"Webdriver quit abnormly, reason: {e}. {self.RETRY_TIMES_LIMIT} retry times left.") @@ -399,19 +388,22 @@ def _get_all_data(self, driver, user_id, userid_index): logging.info( f"Get year power charge for {user_id} successfully, yealrly charge is {yearly_charge} CNY") + # 按月获取数据 + month, month_usage, month_charge = self._get_month_usage(driver) + # get yesterday usage last_daily_date, last_daily_usage = self._get_yesterday_usage(driver) + if month is None: + logging.error(f"Get month power usage for {user_id} failed, pass") + # 新增储存用电量 if self.enable_database_storage: # 将数据存储到数据库 logging.info("enable_database_storage is true, we will store the data to the database.") # 按天获取数据 7天/30天 date, usages = self._get_daily_usage_data(driver) - # 按月获取数据 - month, month_usage, month_charge = self._get_month_usage(driver) - if month is None: - logging.error(f"Get month power usage for {user_id} failed, pass") + self._save_user_data(user_id, balance, last_daily_date, last_daily_usage, date, usages, month, month_usage, month_charge, yearly_charge, yearly_usage) else: logging.info("enable_database_storage is false, we will not store the data to the database.") @@ -420,8 +412,6 @@ def _get_all_data(self, driver, user_id, userid_index): else: logging.info( f"Get daily power consumption for {user_id} successfully, , {last_daily_date} usage is {last_daily_usage} kwh.") - - self._save_user_data(user_id, balance, last_daily_date, last_daily_usage, date, usages, month, month_usage, month_charge, yearly_charge, yearly_usage) if month_charge: month_charge = month_charge[-1] diff --git a/scripts/main.py b/scripts/main.py index 677db32..9de10cf 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -1,21 +1,18 @@ import logging import logging.config -import requests import os import sys import time -from datetime import datetime,timedelta - -import dotenv import schedule - +from datetime import datetime,timedelta from const import * from data_fetcher import DataFetcher def main(): - # 读取 .env 文件 - dotenv.load_dotenv(verbose=True) + if 'PYTHON_IN_DOCKER' not in os.environ: + # 读取 .env 文件 + dotenv.load_dotenv(verbose=True) global RETRY_TIMES_LIMIT try: PHONE_NUMBER = os.getenv("PHONE_NUMBER") diff --git a/scripts/sensor_updator.py b/scripts/sensor_updator.py index 25fba0b..7875948 100644 --- a/scripts/sensor_updator.py +++ b/scripts/sensor_updator.py @@ -1,7 +1,6 @@ import logging import os from datetime import datetime -from dateutil.relativedelta import relativedelta import requests from sympy import true @@ -77,8 +76,8 @@ def update_month_data(self, postfix: str, sensorState: float, usage=False): if usage else MONTH_CHARGE_SENSOR_NAME + postfix ) - last_updated = datetime.now() - relativedelta(months=1) - last_reset = last_updated.strftime("%Y-%m") + last_updated = datetime.now().month - 1 + last_reset = datetime.now().replace(month=last_updated).strftime("%Y-%m") request_body = { "state": sensorState, "unique_id": sensorName,