chore: remove obsolete files and clean up repository
- Deleted unused files including `AGENTS.md`, `data_transmission_example.py`, `delete.py`, and `main.py` to streamline the project structure. - Updated `README.md` to reflect the removal of these files and clarify integration details. - Minor adjustments made to `strings.json` for consistency.
This commit is contained in:
30
AGENTS.md
30
AGENTS.md
@@ -1,30 +0,0 @@
|
|||||||
# Repository Guidelines
|
|
||||||
|
|
||||||
## Project Structure & Module Organization
|
|
||||||
- Energy simulator lives at `main.py`; MQTT examples under `data_transmission_example.py`.
|
|
||||||
- Home Assistant integration is in `custom_components/JackeryHome/` with `__init__.py`, `sensor.py`, `config_flow.py`, translations, and docs.
|
|
||||||
- Branding assets sit in `brands/`; release helpers and docs (e.g., `prepare_release.sh`, `README.md`, `energy_flow_card_config.yaml`) are at the repo root.
|
|
||||||
- Tests currently consist of targeted scripts such as `test_mqtt.py`; add new suites beside related modules.
|
|
||||||
|
|
||||||
## Build, Test, and Development Commands
|
|
||||||
- `uv sync` — install the Python toolchain defined in `pyproject.toml` (uses uv for fast, reproducible envs).
|
|
||||||
- `uv run main.py` — run the MQTT simulator against the broker configured inside the script.
|
|
||||||
- `python test_mqtt.py` — quick publishing/subscription sanity check for MQTT topics.
|
|
||||||
- `./prepare_release.sh` — bump integration metadata and prep a tagged release; review the script before running.
|
|
||||||
|
|
||||||
## Coding Style & Naming Conventions
|
|
||||||
- Python source follows 4-space indentation, snake_case identifiers, and descriptive constants (e.g., `MQTT_BROKER`).
|
|
||||||
- Keep Home Assistant entity IDs lowercase with underscores (`sensor.solar_power`).
|
|
||||||
- Maintain docstrings or top-of-file comments for modules that expose user-facing behavior; prefer concise inline comments for non-obvious logic.
|
|
||||||
- JSON/YAML assets should stay UTF-8, two-space indented, with trailing commas avoided.
|
|
||||||
|
|
||||||
## Testing Guidelines
|
|
||||||
- Favor lightweight integration tests that exercise MQTT flows end-to-end (publish via simulator, assert consumption by HA sensors).
|
|
||||||
- Mirror Home Assistant’s naming pattern: `test_<feature>.py` with `async` helpers where applicable.
|
|
||||||
- Run tests locally before opening a PR; when adding new sensors, include topic fixtures and expected payload assertions.
|
|
||||||
|
|
||||||
## Commit & Pull Request Guidelines
|
|
||||||
- Commits typically use an imperative summary (e.g., "Add inverter sensor mapping") followed by focused changes.
|
|
||||||
- Reference relevant issues in the body (`Fixes #42`) and keep commits scoped so they are reviewable.
|
|
||||||
- Pull requests should describe motivation, outline testing performed (`uv run main.py`, HA log screenshots), and mention any config migrations.
|
|
||||||
- Include UI screenshots/GIFs when altering Lovelace card guidance or other user-facing docs.
|
|
||||||
291
README.md
291
README.md
@@ -1,272 +1,145 @@
|
|||||||
# JackeryHome - Home Assistant 能源监控集成
|
## JackeryHome – Home Assistant Energy Monitoring Integration
|
||||||
|
|
||||||
[](https://github.com/hacs/integration)
|
[](https://github.com/hacs/integration)
|
||||||
[](https://github.com/suyulin/jackery_home/releases)
|
[](https://github.com/suyulin/jackery_home/releases)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
|
|
||||||
这是一个 Home Assistant 自定义集成,通过 MQTT 监控太阳能、电网、电池和家庭能源数据。
|
JackeryHome is a **custom Home Assistant integration** that uses **MQTT** to monitor solar, grid, battery, EPS and home energy data from a Jackery energy system.
|
||||||
|
|
||||||
## 功能
|
The integration is implemented in `custom_components/JackeryHome/sensor.py` and is built around a shared **coordinator** (`JackeryDataCoordinator`) that efficiently manages subscriptions and data requests for all sensors.
|
||||||
|
|
||||||
- 模拟太阳能发电、电网供电、家庭用电和电池充放电数据
|
|
||||||
- 通过 MQTT 自动发现功能将传感器添加到 Home Assistant
|
|
||||||
- **提供 Home Assistant 自定义集成,用于接收和显示 MQTT 数据**
|
|
||||||
- 提供 Energy Flow Card Plus 卡片配置示例
|
|
||||||
|
|
||||||
## 项目结构
|
### Features
|
||||||
|
|
||||||
本项目包含两个主要部分:
|
- **Custom Home Assistant integration** (no YAML entities required)
|
||||||
|
- **MQTT-based data flow** with a shared `JackeryDataCoordinator`
|
||||||
|
- Periodic `data_get` requests every **5 seconds** for all sensors
|
||||||
|
- Real-time **power sensors** (W) and cumulative **energy sensors** (kWh)
|
||||||
|
- **Battery SoC** in percent with proper scaling
|
||||||
|
- Ready-to-use example configuration for **Energy Flow Card Plus**
|
||||||
|
|
||||||
1. **MQTT 模拟器** (`main.py`) - 模拟发送能源监控数据到 MQTT broker
|
|
||||||
2. **Home Assistant 自定义集成** (`custom_components/JackeryHome/`) - 接收 MQTT 数据并创建传感器实体
|
|
||||||
|
|
||||||
### 集成架构
|
### Prerequisites
|
||||||
|
|
||||||
集成采用**协调器模式**(Coordinator Pattern):
|
Before the JackeryHome integration can receive any data, **two things must be in place**:
|
||||||
- 所有传感器共享一个 `JackeryDataCoordinator` 实例
|
|
||||||
- 统一管理 MQTT 订阅和数据请求
|
|
||||||
- 每 5 秒发送一次包含所有传感器 `meter_sn` 的数据请求
|
|
||||||
- 自动解析响应并分发给对应的传感器实体
|
|
||||||
|
|
||||||
## 传感器列表
|
1. **MQTT broker/server is configured and reachable**
|
||||||
|
|
||||||
本项目会创建以下传感器:
|
- A running MQTT broker (e.g. Mosquitto, EMQX, etc.) is required.
|
||||||
|
- Home Assistant's built‑in **MQTT integration** must be configured to connect to this broker.
|
||||||
|
- The broker address, port, username/password (if any) should match what your device and simulator are using.
|
||||||
|
- In your MQTT configuration, **replace the IP with the address of your own MQTT server**.
|
||||||
|

|
||||||
|

|
||||||
|
2. **Device is configured from the JackeryHome app**
|
||||||
|
|
||||||
### 功率传感器(实时监测)
|
- Use the vendor/JackeryHome mobile app to add the device/gateway and complete its initial setup.
|
||||||
|
- Make sure the device has network access and is configured so that it can connect to your MQTT/cloud backend.
|
||||||
|
- In the Jackery Home app, long-press the app logo to open the configuration screen.
|
||||||
|
- In the Jackery Home app configuration, **replace the IP with the address of your own MQTT server**.
|
||||||
|

|
||||||
|
|
||||||
- `sensor.jackeryhome_solar_power`: 太阳能发电功率(W)
|
---
|
||||||
- `sensor.jackeryhome_home_power`: 家庭用电功率(W)
|
|
||||||
- `sensor.jackeryhome_grid_import`: 从电网购买功率(W)
|
|
||||||
- `sensor.jackeryhome_grid_export`: 向电网出售功率(W)
|
|
||||||
- `sensor.jackeryhome_battery_charge`: 电池充电功率(W)
|
|
||||||
- `sensor.jackeryhome_battery_discharge`: 电池放电功率(W)
|
|
||||||
- `sensor.jackeryhome_battery_state_of_charge`: 电池电量百分比(%)
|
|
||||||
|
|
||||||
### 能源传感器(用于能源仪表板)
|
### Installation
|
||||||
|
|
||||||
- `sensor.jackeryhome_solar_energy`: 太阳能发电总量(kWh)
|
#### Option A: Install via HACS (recommended)
|
||||||
- `sensor.jackeryhome_home_energy`: 家庭用电总量(kWh)
|
|
||||||
- `sensor.jackeryhome_grid_import_energy`: 电网购买总量(kWh)
|
|
||||||
- `sensor.jackeryhome_grid_export_energy`: 电网出售总量(kWh)
|
|
||||||
- `sensor.jackeryhome_battery_charge_energy`: 电池充电总量(kWh)
|
|
||||||
- `sensor.jackeryhome_battery_discharge_energy`: 电池放电总量(kWh)
|
|
||||||
|
|
||||||
## 安装
|
1. **Add custom repository**
|
||||||
|
|
||||||
### 方式一:通过 HACS 安装(推荐)
|
- Open HACS in Home Assistant
|
||||||
|
- Click the three dots in the top-right → **Custom repositories**
|
||||||
|
- Add repository URL: `https://github.com/suyulin/jackery_home`
|
||||||
|
- Category: `Integration`
|
||||||
|
- Click **Add**
|
||||||
|
2. **Install the integration**
|
||||||
|
|
||||||
1. **添加自定义存储库**
|
- In HACS, search for **"JackeryHome"**
|
||||||
- 打开 HACS
|
- Click **Install**
|
||||||
- 点击右上角三个点 → "自定义存储库"
|
- Restart Home Assistant
|
||||||
- 添加仓库 URL:`https://github.com/suyulin/jackery_home`
|
3. **Configure the integration**
|
||||||
- 类别选择:`Integration`
|
|
||||||
- 点击"添加"
|
|
||||||
|
|
||||||
2. **安装集成**
|
- Go to **Settings → Devices & Services → Add Integration**
|
||||||
- 在 HACS 中搜索 "JackeryHome"
|
- Search for **"JackeryHome"**
|
||||||
- 点击"安装"
|
- Enter an MQTT topic prefix if needed (default: `homeassistant/sensor`)
|
||||||
- 重启 Home Assistant
|
- Submit to finish configuration
|
||||||
|

|
||||||
|

|
||||||
|
> **Requirement**: The built-in **MQTT integration** must be configured and connected to your MQTT broker **before** JackeryHome will work.
|
||||||
|
|
||||||
3. **配置集成**
|
### Example: Energy Flow Card Plus
|
||||||
- 进入 **设置** → **设备与服务** → **添加集成**
|
|
||||||
- 搜索 "JackeryHome"
|
|
||||||
- 输入 MQTT 主题前缀(默认:`homeassistant/sensor`)
|
|
||||||
- 点击提交完成配置
|
|
||||||
|
|
||||||
### 方式二:手动安装
|
You can use these sensors with the [Energy Flow Card Plus](https://github.com/flixlix/energy-flow-card-plus) Lovelace card.
|
||||||
|
|
||||||
1. 下载最新的 [Release](https://github.com/suyulin/jackery_home/releases)
|
#### Install the card
|
||||||
2. 将 `custom_components/JackeryHome` 文件夹复制到你的 Home Assistant 配置目录的 `custom_components/` 文件夹中
|
|
||||||
3. 重启 Home Assistant
|
|
||||||
4. 按照上述"配置集成"步骤进行配置
|
|
||||||
|
|
||||||
## 快速开始
|
- Via HACS (recommended):
|
||||||
|
|
||||||
### 使用 MQTT 模拟器
|
- HACS → **Frontend** → search for **"Energy Flow Card Plus"** → install → restart HA.
|
||||||
|
- Manual:
|
||||||
|
|
||||||
1. **安装依赖并运行模拟器**
|
- Download from the GitHub repository.
|
||||||
```bash
|
- Place files under `www/community/energy-flow-card-plus/`.
|
||||||
# 使用 uv(推荐)
|
- Add a Lovelace resource pointing to `/hacsfiles/energy-flow-card-plus/energy-flow-card-plus.js` (type: JavaScript module).
|
||||||
uv sync
|
|
||||||
uv run main.py
|
|
||||||
|
|
||||||
# 或使用 pip
|
#### Basic configuration example
|
||||||
pip install paho-mqtt
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **配置 MQTT Broker**
|
|
||||||
|
|
||||||
编辑 `main.py` 中的地址:
|
|
||||||
```python
|
|
||||||
MQTT_BROKER = "192.168.0.101" # 修改为你的 MQTT Broker 地址
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **在 Home Assistant 中查看传感器**
|
|
||||||
|
|
||||||
传感器会自动通过 MQTT Discovery 添加
|
|
||||||
|
|
||||||
### 配置和使用
|
|
||||||
|
|
||||||
1. **确保已安装并配置集成**(参考上面的安装步骤)
|
|
||||||
|
|
||||||
2. **运行模拟器**
|
|
||||||
```bash
|
|
||||||
# 使用 uv(推荐)
|
|
||||||
uv run main.py
|
|
||||||
|
|
||||||
# 或使用 python
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **查看传感器数据**
|
|
||||||
- 进入 **开发者工具** → **状态**
|
|
||||||
- 搜索 "jackeryhome" 或传感器名称(如 "Solar Power"、"Home Power" 等)
|
|
||||||
- 实体 ID 格式:`sensor.jackeryhome_{sensor_id}`
|
|
||||||
|
|
||||||
## Energy Flow Card Plus 配置
|
|
||||||
|
|
||||||
### 安装卡片
|
|
||||||
|
|
||||||
1. **通过 HACS 安装(推荐):**
|
|
||||||
- 打开 HACS
|
|
||||||
- 点击"前端"(Frontend)
|
|
||||||
- 搜索 "Energy Flow Card Plus"
|
|
||||||
- 点击安装
|
|
||||||
- 重启 Home Assistant
|
|
||||||
|
|
||||||
2. **手动安装:**
|
|
||||||
- 从 [GitHub](https://github.com/flixlix/energy-flow-card-plus) 下载最新版本
|
|
||||||
- 将文件放到 `www/community/energy-flow-card-plus/` 目录
|
|
||||||
- 在 Home Assistant 中添加资源:
|
|
||||||
- 设置 -> 仪表板 -> 右上角三点 -> 资源
|
|
||||||
- URL: `/hacsfiles/energy-flow-card-plus/energy-flow-card-plus.js`
|
|
||||||
- 类型: JavaScript 模块
|
|
||||||
|
|
||||||
### 添加卡片到仪表板
|
|
||||||
|
|
||||||
1. 进入仪表板编辑模式
|
|
||||||
2. 点击"添加卡片"
|
|
||||||
3. 选择"手动"(Manual)
|
|
||||||
4. 复制 `energy_flow_card_config.yaml` 中的配置
|
|
||||||
5. 保存
|
|
||||||
|
|
||||||
### 基础配置示例
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
type: custom:energy-flow-card-plus
|
type: custom:energy-flow-card-plus
|
||||||
entities:
|
entities:
|
||||||
solar:
|
solar:
|
||||||
entity: sensor.jackeryhome_solar_power
|
entity: sensor.solar_power
|
||||||
name: 太阳能
|
name: Solar
|
||||||
icon: mdi:solar-power
|
icon: mdi:solar-power
|
||||||
grid:
|
grid:
|
||||||
entity:
|
entity:
|
||||||
consumption: sensor.jackeryhome_grid_import # 从电网购买
|
consumption: sensor.grid_import_power # buying from grid
|
||||||
production: sensor.jackeryhome_grid_export # 向电网出售
|
production: sensor.grid_export_power # selling to grid
|
||||||
name: 电网
|
name: Grid
|
||||||
icon: mdi:transmission-tower
|
icon: mdi:transmission-tower
|
||||||
battery:
|
battery:
|
||||||
entity:
|
entity:
|
||||||
consumption: sensor.jackeryhome_battery_charge # 充电
|
consumption: sensor.battery_charge_power # charging
|
||||||
production: sensor.jackeryhome_battery_discharge # 放电
|
production: sensor.battery_discharge_power # discharging
|
||||||
state_of_charge: sensor.jackeryhome_battery_state_of_charge
|
state_of_charge: sensor.battery_soc
|
||||||
name: 电池
|
name: Battery
|
||||||
icon: mdi:battery
|
icon: mdi:battery
|
||||||
home:
|
home:
|
||||||
entity: sensor.jackeryhome_home_power
|
entity: sensor.home_power
|
||||||
name: 家庭用电
|
name: Home
|
||||||
icon: mdi:home-lightning-bolt
|
icon: mdi:home-lightning-bolt
|
||||||
display_zero_lines:
|
display_zero_lines:
|
||||||
mode: show
|
mode: show
|
||||||
transparency: 50
|
transparency: 50
|
||||||
grey_color:
|
grey_color: [189, 189, 189]
|
||||||
- 189
|
|
||||||
- 189
|
|
||||||
- 189
|
|
||||||
w_decimals: 0
|
w_decimals: 0
|
||||||
kw_decimals: 2
|
kw_decimals: 2
|
||||||
color_icons: true
|
color_icons: true
|
||||||
animation_speed: 10
|
animation_speed: 10
|
||||||
energy_date_selection: false
|
energy_date_selection: false
|
||||||
```
|
```
|
||||||
|

|
||||||
|
|
||||||
**注意**:实体 ID 格式为 `sensor.jackeryhome_{sensor_id}`,其中 `{sensor_id}` 对应传感器 ID(如 `solar_power`、`grid_import` 等)。
|
### Notes & Requirements
|
||||||
|
|
||||||
更多配置选项请查看 `energy_flow_card_config.yaml` 文件。
|
- The MQTT broker must be running before you start the simulator or expect data in Home Assistant.
|
||||||
|
- The integration sends a single `data_get` request every 5 seconds for **all sensors**, reducing MQTT traffic.
|
||||||
|
- The device serial number (`device_sn`) is automatically obtained from LWT messages; no manual configuration is required.
|
||||||
|
- When the MQTT broker is unavailable, the coordinator logs a warning and retries automatically.
|
||||||
|
|
||||||
## 项目文件说明
|
|
||||||
|
|
||||||
### 核心文件
|
---
|
||||||
- `main.py`: MQTT 传感器模拟器主程序
|
|
||||||
- `custom_components/JackeryHome/`: Home Assistant 自定义集成
|
|
||||||
- `__init__.py`: 集成入口
|
|
||||||
- `manifest.json`: 集成元数据
|
|
||||||
- `sensor.py`: 传感器平台实现(包含协调器模式和所有传感器逻辑)
|
|
||||||
- `config_flow.py`: UI 配置流程
|
|
||||||
- `strings.json`: 本地化字符串
|
|
||||||
- `translations/zh-Hans.json`: 中文翻译
|
|
||||||
- `README.md`: 集成技术文档(包含架构设计、MQTT 协议格式等)
|
|
||||||
|
|
||||||
### 文档和工具
|
### Links
|
||||||
- `INTEGRATION_GUIDE.md`: 详细的集成使用指南
|
|
||||||
- `energy_flow_card_config.yaml`: Energy Flow Card Plus 配置示例
|
|
||||||
- `install.sh`: Linux/macOS 自动安装脚本
|
|
||||||
- `install.ps1`: Windows PowerShell 自动安装脚本
|
|
||||||
- `README.md`: 项目主文档(本文件)
|
|
||||||
|
|
||||||
## 数据流向逻辑
|
- **Energy Flow Card Plus** – `https://github.com/flixlix/energy-flow-card-plus`
|
||||||
|
- **Home Assistant MQTT Discovery** – `https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery`
|
||||||
|
- **Home Assistant Developer Docs** – `https://developers.home-assistant.io/`
|
||||||
|
- **Paho MQTT Python Client** – `https://github.com/eclipse/paho.mqtt.python`
|
||||||
|
|
||||||
1. **太阳能发电**:随机生成 200-3000W
|
---
|
||||||
2. **家庭用电**:随机生成 500-3500W
|
|
||||||
3. **电网功率**:
|
|
||||||
- grid_import(从电网购买):当家庭用电 > 太阳能发电时的差值
|
|
||||||
- grid_export(向电网出售):当太阳能发电 > 家庭用电时的差值
|
|
||||||
4. **电池功率**:
|
|
||||||
- battery_charge(充电):0-1000W
|
|
||||||
- battery_discharge(放电):0-1000W
|
|
||||||
5. **电池电量**:根据充放电动态变化(20%-100%)
|
|
||||||
|
|
||||||
## 注意事项
|
### License
|
||||||
|
|
||||||
- 确保 Home Assistant 已配置好 MQTT 集成
|
|
||||||
- MQTT Broker 需要在运行此脚本之前启动
|
|
||||||
- 集成会每 5 秒主动请求一次数据(所有传感器共享同一个请求)
|
|
||||||
- 数据为模拟值,用于演示目的
|
|
||||||
- 集成会自动从 LWT 消息获取设备序列号,无需手动配置
|
|
||||||
|
|
||||||
## 文档
|
|
||||||
|
|
||||||
- [**HACS 发布指南**](HACS_PUBLISHING_GUIDE.md) - 如何发布到 HACS
|
|
||||||
- [自定义集成 README](custom_components/JackeryHome/README.md) - 集成技术文档
|
|
||||||
|
|
||||||
## 开发者
|
|
||||||
|
|
||||||
### 发布新版本
|
|
||||||
|
|
||||||
使用提供的发布脚本:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./prepare_release.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
或手动发布:
|
|
||||||
|
|
||||||
1. 更新 `custom_components/JackeryHome/manifest.json` 中的版本号
|
|
||||||
2. 提交更改并推送到 GitHub
|
|
||||||
3. 创建新的 Git tag(如 `v1.0.1`)
|
|
||||||
4. 在 GitHub 创建 Release
|
|
||||||
|
|
||||||
详细说明请查看 [HACS 发布指南](HACS_PUBLISHING_GUIDE.md)
|
|
||||||
|
|
||||||
## 相关链接
|
|
||||||
|
|
||||||
- [Energy Flow Card Plus GitHub](https://github.com/flixlix/energy-flow-card-plus)
|
|
||||||
- [Home Assistant MQTT Discovery](https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery)
|
|
||||||
- [Home Assistant 开发文档](https://developers.home-assistant.io/)
|
|
||||||
- [Paho MQTT Python Client](https://github.com/eclipse/paho.mqtt.python)
|
|
||||||
|
|
||||||
## 许可证
|
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
|
|||||||
@@ -1,272 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
数据传输示例
|
|
||||||
演示如何使用修改后的 Energy Monitor 系统进行数据传输
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
import random
|
|
||||||
import paho.mqtt.client as mqtt
|
|
||||||
battery_soc_point = "21548033"
|
|
||||||
## 能量累计
|
|
||||||
solar_energy_point = "16961537"
|
|
||||||
home_energy_point = "16980993"
|
|
||||||
grid_import_energy_point = "16969729"
|
|
||||||
grid_export_energy_point = "16970753"
|
|
||||||
battery_charge_energy_point = "16964609"
|
|
||||||
battery_discharge_energy_point = "16965633"
|
|
||||||
## 实时功率
|
|
||||||
solar_power_point = "1026001"
|
|
||||||
home_power_point = "21171201"
|
|
||||||
grid_import_power_point = "16930817"
|
|
||||||
grid_export_power_point = "16930817"
|
|
||||||
battery_charge_power_point = "16931841"
|
|
||||||
battery_discharge_power_point = "16931841"
|
|
||||||
class DataTransmissionExample:
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, broker="192.168.1.100", port=1883):
|
|
||||||
self.broker = broker
|
|
||||||
self.port = port
|
|
||||||
self.client = None
|
|
||||||
self.running = False
|
|
||||||
self.device_status = "offline"
|
|
||||||
self.device_sn = ""
|
|
||||||
self.battery_soc = 0
|
|
||||||
self.solar_energy = 0
|
|
||||||
self.solar_energy = 0
|
|
||||||
self.home_energy = 0
|
|
||||||
self.grid_import_energy = 0
|
|
||||||
self.grid_export_energy = 0
|
|
||||||
self.battery_charge_energy = 0
|
|
||||||
self.battery_discharge_energy = 0
|
|
||||||
|
|
||||||
self.energy_data = {
|
|
||||||
"solar_energy": 0,
|
|
||||||
"home_energy": 0,
|
|
||||||
"grid_import_energy": 0,
|
|
||||||
"grid_export_energy": 0,
|
|
||||||
"battery_charge_energy": 0,
|
|
||||||
"battery_discharge_energy": 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
## 构造发送数据
|
|
||||||
def construct_send_data(self):
|
|
||||||
data = {
|
|
||||||
"cmd": "data_get",
|
|
||||||
"gw_sn": self.device_sn,
|
|
||||||
"timestamp": str(int(time.time() * 1000)),
|
|
||||||
## 随机数是字符串
|
|
||||||
"token": str(random.randint(1000, 9999)),
|
|
||||||
"info": {
|
|
||||||
"dev_list": [
|
|
||||||
{
|
|
||||||
"dev_sn": "ems_" + self.device_sn,
|
|
||||||
"meter_list": [
|
|
||||||
battery_soc_point,
|
|
||||||
solar_energy_point,
|
|
||||||
home_energy_point,
|
|
||||||
grid_import_energy_point,
|
|
||||||
grid_export_energy_point,
|
|
||||||
battery_charge_energy_point,
|
|
||||||
battery_discharge_energy_point,
|
|
||||||
solar_power_point,
|
|
||||||
home_power_point,
|
|
||||||
grid_import_power_point,
|
|
||||||
grid_export_power_point,
|
|
||||||
battery_charge_power_point,
|
|
||||||
battery_discharge_power_point,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
## 解析数据
|
|
||||||
def parse_data(self, payload):
|
|
||||||
# payload 已经是字典类型,不需要再次解析
|
|
||||||
if isinstance(payload, str):
|
|
||||||
data = json.loads(payload)
|
|
||||||
else:
|
|
||||||
data = payload
|
|
||||||
info = data["info"]
|
|
||||||
dev_list = info["dev_list"]
|
|
||||||
for dev in dev_list:
|
|
||||||
dev_sn = dev["dev_sn"]
|
|
||||||
meter_list = dev["meter_list"]
|
|
||||||
for meter in meter_list:
|
|
||||||
meter_sn = meter[0]
|
|
||||||
# 先转换为 float,然后判断是否可以转换为 int
|
|
||||||
meter_value_float = float(meter[1])
|
|
||||||
# 如果小数部分为 0,则转换为 int,否则保留 float
|
|
||||||
meter_value = int(meter_value_float) if meter_value_float == int(meter_value_float) else meter_value_float
|
|
||||||
print(f"📨 收到设备数据: {dev_sn} {meter_sn} {meter_value}")
|
|
||||||
if meter_sn == battery_soc_point:
|
|
||||||
self.battery_soc = meter_value
|
|
||||||
print(f"📨 收到电池电量: {self.battery_soc}")
|
|
||||||
if meter_sn == solar_energy_point:
|
|
||||||
self.solar_energy = meter_value
|
|
||||||
print(f"📨 收到太阳能能量: {self.solar_energy}")
|
|
||||||
if meter_sn == home_energy_point:
|
|
||||||
self.home_energy = meter_value
|
|
||||||
print(f"📨 收到家庭能量: {self.home_energy}")
|
|
||||||
if meter_sn == grid_import_energy_point:
|
|
||||||
self.grid_import_energy = meter_value
|
|
||||||
print(f"📨 收到电网购买能量: {self.grid_import_energy}")
|
|
||||||
if meter_sn == grid_export_energy_point:
|
|
||||||
self.grid_export_energy = meter_value
|
|
||||||
print(f"📨 收到电网出售能量: {self.grid_export_energy}")
|
|
||||||
if meter_sn == battery_charge_energy_point:
|
|
||||||
self.battery_charge_energy = meter_value
|
|
||||||
print(f"📨 收到电池充电能量: {self.battery_charge_energy}")
|
|
||||||
if meter_sn == battery_discharge_energy_point:
|
|
||||||
self.battery_discharge_energy = meter_value
|
|
||||||
print(f"📨 收到电池放电能量: {self.battery_discharge_energy}")
|
|
||||||
if meter_sn == solar_power_point:
|
|
||||||
self.solar_power = meter_value
|
|
||||||
print(f"📨 收到太阳能功率: {self.solar_power}")
|
|
||||||
if meter_sn == home_power_point:
|
|
||||||
self.home_power = meter_value
|
|
||||||
print(f"📨 收到家庭功率: {self.home_power}")
|
|
||||||
## 电网功率 负值为购买,正值为出售
|
|
||||||
if meter_sn == grid_import_power_point:
|
|
||||||
self.grid_import_power = meter_value
|
|
||||||
if meter_value < 0:
|
|
||||||
self.grid_import_power = -meter_value
|
|
||||||
print(f"📨 收到电网购买功率: {self.grid_import_power}")
|
|
||||||
else:
|
|
||||||
self.grid_export_power = meter_value
|
|
||||||
print(f"📨 收到电网出售功率: {self.grid_export_power}")
|
|
||||||
## 电池充放电功率 负值为充电,正值为放电
|
|
||||||
if meter_sn == battery_charge_power_point:
|
|
||||||
self.battery_charge_power = meter_value
|
|
||||||
if meter_value < 0:
|
|
||||||
self.battery_charge_power = -meter_value
|
|
||||||
print(f"📨 收到电池充电功率: {self.battery_charge_power}")
|
|
||||||
else:
|
|
||||||
self.battery_discharge_power = meter_value
|
|
||||||
print(f"📨 收到电池放电功率: {self.battery_discharge_power}")
|
|
||||||
|
|
||||||
def setup_mqtt(self):
|
|
||||||
"""设置 MQTT 客户端"""
|
|
||||||
self.client = mqtt.Client(client_id="energy_device", callback_api_version=mqtt.CallbackAPIVersion.VERSION2)
|
|
||||||
self.client.on_connect = self.on_connect
|
|
||||||
self.client.on_message = self.on_message
|
|
||||||
|
|
||||||
def on_connect(self, client, userdata, flags, rc, properties):
|
|
||||||
"""MQTT 连接回调"""
|
|
||||||
if rc == 0:
|
|
||||||
print("✅ 连接到 MQTT 代理成功")
|
|
||||||
# 订阅数据获取请求主题
|
|
||||||
client.subscribe("v1/iot_gw/gw/data")
|
|
||||||
client.subscribe("v1/iot_gw/gw_lwt")
|
|
||||||
print("✅ 订阅 v1/iot_gw/gw_data 主题成功")
|
|
||||||
print("✅ 订阅 v1/iot_gw/gw_lwt 主题成功")
|
|
||||||
else:
|
|
||||||
print(f"❌ 连接 MQTT 代理失败,错误码: {rc}")
|
|
||||||
|
|
||||||
def on_message(self, client, userdata, msg):
|
|
||||||
"""MQTT 消息接收回调"""
|
|
||||||
if msg.topic == "v1/iot_gw/gw/data":
|
|
||||||
print(f"📨 收到数据请求: {msg.payload.decode()}")
|
|
||||||
# 解析JSON
|
|
||||||
data = json.loads(msg.payload)
|
|
||||||
self.parse_data(data)
|
|
||||||
if msg.topic == "v1/iot_gw/gw_lwt":
|
|
||||||
print(f"📨 收到设备状态: {msg.payload.decode()}")
|
|
||||||
# 解析JSON
|
|
||||||
data = json.loads(msg.payload)
|
|
||||||
self.device_sn = data["gw_sn"]
|
|
||||||
info = data["info"]
|
|
||||||
print(f"📨 收到设备状态: {self.device_sn} {info}")
|
|
||||||
# 更新设备状态
|
|
||||||
self.device_status = info
|
|
||||||
print(f"📨 设备状态: {self.device_status}")
|
|
||||||
|
|
||||||
|
|
||||||
def send_device_data(self):
|
|
||||||
data = self.construct_send_data()
|
|
||||||
|
|
||||||
# 转换为 JSON 格式
|
|
||||||
json_data = json.dumps(data, ensure_ascii=False, indent=2)
|
|
||||||
|
|
||||||
# 发布到 device/data 主题
|
|
||||||
result = self.client.publish("v1/iot_gw/cloud/data", json_data)
|
|
||||||
|
|
||||||
if result.rc == mqtt.MQTT_ERR_SUCCESS:
|
|
||||||
print("📤 发送设备数据:")
|
|
||||||
print(f" 主题: v1/iot_gw/cloud/data")
|
|
||||||
print(f" 数据: {json_data}")
|
|
||||||
print()
|
|
||||||
else:
|
|
||||||
print(f"❌ 发送数据失败,错误码: {result.rc}")
|
|
||||||
|
|
||||||
def start_simulation(self, duration=60):
|
|
||||||
"""启动数据模拟"""
|
|
||||||
print("🚀 启动数据传输模拟")
|
|
||||||
print(f"📡 MQTT 代理: {self.broker}:{self.port}")
|
|
||||||
print(f"⏱️ 运行时长: {duration} 秒")
|
|
||||||
print("=" * 50)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 连接 MQTT 代理
|
|
||||||
self.client.connect(self.broker, self.port, 60)
|
|
||||||
self.client.loop_start()
|
|
||||||
self.running = True
|
|
||||||
|
|
||||||
# 等待连接建立
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 发送初始数据
|
|
||||||
print("📤 发送初始数据...")
|
|
||||||
if self.device_sn != "":
|
|
||||||
self.send_device_data()
|
|
||||||
else:
|
|
||||||
print("❌ 设备SN为空,无法发送数据")
|
|
||||||
# return
|
|
||||||
|
|
||||||
# 运行指定时间
|
|
||||||
start_time = time.time()
|
|
||||||
while self.running and (time.time() - start_time) < duration:
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# 每5秒发送一次数据(模拟设备主动发送)
|
|
||||||
if int(time.time() - start_time) % 5 == 0:
|
|
||||||
print("📤 设备主动发送数据...")
|
|
||||||
if self.device_sn != "":
|
|
||||||
self.send_device_data()
|
|
||||||
else:
|
|
||||||
print("❌ 设备SN为空,无法发送数据")
|
|
||||||
# return
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("\n⏹️ 用户中断模拟")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ 模拟出错: {e}")
|
|
||||||
finally:
|
|
||||||
self.stop_simulation()
|
|
||||||
|
|
||||||
def stop_simulation(self):
|
|
||||||
"""停止模拟"""
|
|
||||||
self.running = False
|
|
||||||
if self.client:
|
|
||||||
self.client.loop_stop()
|
|
||||||
self.client.disconnect()
|
|
||||||
print("✅ 模拟已停止")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""主函数"""
|
|
||||||
print("🏠 Energy Monitor 数据传输示例")
|
|
||||||
print("=" * 50)
|
|
||||||
print()
|
|
||||||
|
|
||||||
# 创建示例实例
|
|
||||||
example = DataTransmissionExample()
|
|
||||||
example.setup_mqtt()
|
|
||||||
|
|
||||||
# 启动模拟(运行60秒)
|
|
||||||
example.start_simulation(duration=1000)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
54
delete.py
54
delete.py
@@ -1,54 +0,0 @@
|
|||||||
import json
|
|
||||||
import paho.mqtt.client as mqtt
|
|
||||||
|
|
||||||
MQTT_BROKER = "192.168.1.100"
|
|
||||||
MQTT_PORT = 1883
|
|
||||||
MQTT_USERNAME = ""
|
|
||||||
MQTT_PASSWORD = ""
|
|
||||||
MQTT_CLIENT_ID = "ha_delete_discovery"
|
|
||||||
|
|
||||||
SENSOR_IDS = [
|
|
||||||
"solar_power",
|
|
||||||
"home_power",
|
|
||||||
"grid_import",
|
|
||||||
"grid_export",
|
|
||||||
"battery_charge",
|
|
||||||
"battery_discharge",
|
|
||||||
"battery_soc",
|
|
||||||
"battery_power",
|
|
||||||
"grid_power"
|
|
||||||
]
|
|
||||||
|
|
||||||
# ==== 修改后的回调 ====
|
|
||||||
def on_connect(client, userdata, flags, reason_code, properties=None):
|
|
||||||
if reason_code == 0:
|
|
||||||
print("✅ 已连接到 MQTT Broker")
|
|
||||||
else:
|
|
||||||
print(f"❌ 连接失败,原因码: {reason_code}")
|
|
||||||
|
|
||||||
def on_publish(client, userdata, mid, reason_code, properties=None):
|
|
||||||
print(f"🧹 已发送删除命令 (mid={mid})")
|
|
||||||
|
|
||||||
def delete_discovery_configs():
|
|
||||||
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, MQTT_CLIENT_ID)
|
|
||||||
if MQTT_USERNAME:
|
|
||||||
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
|
|
||||||
|
|
||||||
client.on_connect = on_connect
|
|
||||||
client.on_publish = on_publish
|
|
||||||
|
|
||||||
print("🚀 正在连接 MQTT Broker ...")
|
|
||||||
client.connect(MQTT_BROKER, MQTT_PORT, 60)
|
|
||||||
client.loop_start()
|
|
||||||
|
|
||||||
for sensor_id in SENSOR_IDS:
|
|
||||||
topic = f"homeassistant/sensor/{sensor_id}/config"
|
|
||||||
client.publish(topic, None, retain=True)
|
|
||||||
print(f"🗑️ 已发布空配置以删除实体:{sensor_id}")
|
|
||||||
|
|
||||||
client.loop_stop()
|
|
||||||
client.disconnect()
|
|
||||||
print("✅ 所有 Discovery 配置已删除")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
delete_discovery_configs()
|
|
||||||
BIN
img/app_config_mqtt.png
Normal file
BIN
img/app_config_mqtt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
BIN
img/demo.png
Normal file
BIN
img/demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
BIN
img/jackery_home_add.png
Normal file
BIN
img/jackery_home_add.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 261 KiB |
BIN
img/jackery_home_config.png
Normal file
BIN
img/jackery_home_config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 302 KiB |
BIN
img/mqtt_config.png
Normal file
BIN
img/mqtt_config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
BIN
img/mqtt_config_2.png
Normal file
BIN
img/mqtt_config_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 270 KiB |
191
main.py
191
main.py
@@ -1,191 +0,0 @@
|
|||||||
import json
|
|
||||||
import time
|
|
||||||
import random
|
|
||||||
import paho.mqtt.client as mqtt
|
|
||||||
|
|
||||||
MQTT_BROKER = "192.168.1.100"
|
|
||||||
MQTT_PORT = 1883
|
|
||||||
MQTT_CLIENT_ID = "jackery_home_simulator"
|
|
||||||
|
|
||||||
# 模式控制变量
|
|
||||||
# 0: 自发自用模式 (Self-consumption)
|
|
||||||
# 1: 电池优先模式 (Battery Priority)
|
|
||||||
current_mode = 0
|
|
||||||
|
|
||||||
# 模式名称映射
|
|
||||||
MODE_NAMES = {
|
|
||||||
0: "自发自用模式",
|
|
||||||
1: "电池优先模式"
|
|
||||||
}
|
|
||||||
|
|
||||||
client = mqtt.Client(client_id=MQTT_CLIENT_ID, callback_api_version=mqtt.CallbackAPIVersion.VERSION2)
|
|
||||||
|
|
||||||
# MQTT 连接回调
|
|
||||||
def on_connect(client, userdata, flags, rc, properties):
|
|
||||||
print("Connected to MQTT broker with result code " + str(rc))
|
|
||||||
publish_discovery_configs()
|
|
||||||
# 订阅模式控制命令主题
|
|
||||||
client.subscribe("homeassistant/select/mode_control/set")
|
|
||||||
print("Subscribed to mode control command topic")
|
|
||||||
|
|
||||||
# MQTT 消息接收回调
|
|
||||||
def on_message(client, userdata, msg):
|
|
||||||
global current_mode
|
|
||||||
if msg.topic == "homeassistant/select/mode_control/set":
|
|
||||||
try:
|
|
||||||
payload = msg.payload.decode()
|
|
||||||
# 支持数字或模式名称
|
|
||||||
if payload.isdigit():
|
|
||||||
new_mode = int(payload)
|
|
||||||
elif payload == "自发自用模式":
|
|
||||||
new_mode = 0
|
|
||||||
elif payload == "电池优先模式":
|
|
||||||
new_mode = 1
|
|
||||||
else:
|
|
||||||
print(f"Invalid mode payload: {payload}")
|
|
||||||
return
|
|
||||||
|
|
||||||
if new_mode in [0, 1]:
|
|
||||||
current_mode = new_mode
|
|
||||||
# 发布新的状态(使用模式名称)
|
|
||||||
client.publish("homeassistant/select/mode_control/state", MODE_NAMES[current_mode])
|
|
||||||
print(f"模式已切换到: {MODE_NAMES[current_mode]} ({current_mode})")
|
|
||||||
else:
|
|
||||||
print(f"Invalid mode value: {new_mode}")
|
|
||||||
except ValueError:
|
|
||||||
print(f"Invalid mode payload: {msg.payload.decode()}")
|
|
||||||
|
|
||||||
client.on_connect = on_connect
|
|
||||||
client.on_message = on_message
|
|
||||||
|
|
||||||
|
|
||||||
def publish_discovery_configs():
|
|
||||||
"""发布 Home Assistant MQTT Discovery 配置"""
|
|
||||||
sensors = {
|
|
||||||
"solar_power": {
|
|
||||||
"name": "Solar Power",
|
|
||||||
"unit": "W",
|
|
||||||
"icon": "mdi:solar-power",
|
|
||||||
"device_class": "power",
|
|
||||||
},
|
|
||||||
"home_power": {
|
|
||||||
"name": "Home Power",
|
|
||||||
"unit": "W",
|
|
||||||
"icon": "mdi:home-lightning-bolt",
|
|
||||||
"device_class": "power",
|
|
||||||
},
|
|
||||||
# 电网 - 分为购买和出售
|
|
||||||
"grid_import": {
|
|
||||||
"name": "Grid Import",
|
|
||||||
"unit": "W",
|
|
||||||
"icon": "mdi:transmission-tower-import",
|
|
||||||
"device_class": "power",
|
|
||||||
},
|
|
||||||
"grid_export": {
|
|
||||||
"name": "Grid Export",
|
|
||||||
"unit": "W",
|
|
||||||
"icon": "mdi:transmission-tower-export",
|
|
||||||
"device_class": "power",
|
|
||||||
},
|
|
||||||
# 电池 - 分为充电和放电
|
|
||||||
"battery_charge": {
|
|
||||||
"name": "Battery Charge",
|
|
||||||
"unit": "W",
|
|
||||||
"icon": "mdi:battery-charging",
|
|
||||||
"device_class": "power",
|
|
||||||
},
|
|
||||||
"battery_discharge": {
|
|
||||||
"name": "Battery Discharge",
|
|
||||||
"unit": "W",
|
|
||||||
"icon": "mdi:battery-minus",
|
|
||||||
"device_class": "power",
|
|
||||||
},
|
|
||||||
"battery_soc": {
|
|
||||||
"name": "Battery State of Charge",
|
|
||||||
"unit": "%",
|
|
||||||
"icon": "mdi:battery-70",
|
|
||||||
"device_class": "battery",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for sensor_id, props in sensors.items():
|
|
||||||
topic = f"homeassistant/sensor/{sensor_id}/config"
|
|
||||||
payload = {
|
|
||||||
"name": props["name"],
|
|
||||||
"state_topic": f"homeassistant/sensor/{sensor_id}/state",
|
|
||||||
"unit_of_measurement": props["unit"],
|
|
||||||
"device_class": props["device_class"],
|
|
||||||
"icon": props["icon"],
|
|
||||||
"unique_id": sensor_id,
|
|
||||||
}
|
|
||||||
client.publish(topic, json.dumps(payload), retain=True)
|
|
||||||
print(f"Published discovery config for {sensor_id}")
|
|
||||||
|
|
||||||
# 发布模式控制的 discovery 配置
|
|
||||||
mode_topic = "homeassistant/select/mode_control/config"
|
|
||||||
mode_payload = {
|
|
||||||
"name": "运行模式",
|
|
||||||
"state_topic": "homeassistant/select/mode_control/state",
|
|
||||||
"command_topic": "homeassistant/select/mode_control/set",
|
|
||||||
"options": ["自发自用模式", "电池优先模式"],
|
|
||||||
"icon": "mdi:cog-outline",
|
|
||||||
"unique_id": "mode_control",
|
|
||||||
}
|
|
||||||
client.publish(mode_topic, json.dumps(mode_payload), retain=True)
|
|
||||||
print("Published discovery config for mode_control")
|
|
||||||
|
|
||||||
# 发布初始模式状态(使用模式名称)
|
|
||||||
client.publish("homeassistant/select/mode_control/state", MODE_NAMES[current_mode])
|
|
||||||
print(f"Published initial mode state: {MODE_NAMES[current_mode]} ({current_mode})")
|
|
||||||
|
|
||||||
|
|
||||||
def publish_sensor_data():
|
|
||||||
"""定期发布模拟功率数据"""
|
|
||||||
battery_soc = random.uniform(20, 100) # 初始电池电量
|
|
||||||
|
|
||||||
while True:
|
|
||||||
solar = random.uniform(200, 3000) # 太阳能发电
|
|
||||||
home = random.uniform(500, 3500) # 家庭负载
|
|
||||||
grid = home - solar # 电网供电(可能为负)
|
|
||||||
battery = random.uniform(-1000, 1000) # 电池充/放电
|
|
||||||
|
|
||||||
# 将电网功率分离为购买(import)和出售(export)
|
|
||||||
grid_import = max(0, grid) # 从电网购买(正值)
|
|
||||||
grid_export = max(0, -grid) # 向电网出售(转为正值)
|
|
||||||
|
|
||||||
# 将电池功率分离为充电和放电
|
|
||||||
battery_charge = max(0, -battery) # 充电(转为正值)
|
|
||||||
battery_discharge = max(0, battery) # 放电(正值)
|
|
||||||
|
|
||||||
# 根据电池充放电模拟电量变化
|
|
||||||
if battery < 0: # 充电
|
|
||||||
battery_soc = min(100, battery_soc + 0.5)
|
|
||||||
elif battery > 0: # 放电
|
|
||||||
battery_soc = max(0, battery_soc - 0.3)
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"solar_power": round(solar, 2),
|
|
||||||
"home_power": round(home, 2),
|
|
||||||
"grid_import": round(grid_import, 2),
|
|
||||||
"grid_export": round(grid_export, 2),
|
|
||||||
"battery_charge": round(battery_charge, 2),
|
|
||||||
"battery_discharge": round(battery_discharge, 2),
|
|
||||||
"battery_soc": round(battery_soc, 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value in data.items():
|
|
||||||
topic = f"homeassistant/sensor/{key}/state"
|
|
||||||
client.publish(topic, value)
|
|
||||||
|
|
||||||
# 发布当前模式状态
|
|
||||||
client.publish("homeassistant/select/mode_control/state", MODE_NAMES[current_mode])
|
|
||||||
|
|
||||||
print("Published:", data, f"| 运行模式: {MODE_NAMES[current_mode]}")
|
|
||||||
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
client.connect(MQTT_BROKER, MQTT_PORT, 60)
|
|
||||||
client.loop_start()
|
|
||||||
publish_sensor_data()
|
|
||||||
Reference in New Issue
Block a user