pyatomberg 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyatomberg-0.1.0/.github/workflows/ci.yml +33 -0
- pyatomberg-0.1.0/.github/workflows/publish.yml +36 -0
- pyatomberg-0.1.0/.gitignore +49 -0
- pyatomberg-0.1.0/HANDOVER.md +277 -0
- pyatomberg-0.1.0/LICENSE +622 -0
- pyatomberg-0.1.0/PKG-INFO +336 -0
- pyatomberg-0.1.0/README.md +309 -0
- pyatomberg-0.1.0/pyatomberg/__init__.py +79 -0
- pyatomberg-0.1.0/pyatomberg/auth/__init__.py +6 -0
- pyatomberg-0.1.0/pyatomberg/auth/cognito.py +177 -0
- pyatomberg-0.1.0/pyatomberg/auth/developer.py +121 -0
- pyatomberg-0.1.0/pyatomberg/auth/interactive_oauth.py +100 -0
- pyatomberg-0.1.0/pyatomberg/client.py +230 -0
- pyatomberg-0.1.0/pyatomberg/const.py +43 -0
- pyatomberg-0.1.0/pyatomberg/crypto.py +83 -0
- pyatomberg-0.1.0/pyatomberg/exceptions.py +28 -0
- pyatomberg-0.1.0/pyatomberg/fan/__init__.py +6 -0
- pyatomberg-0.1.0/pyatomberg/fan/device.py +151 -0
- pyatomberg-0.1.0/pyatomberg/fan/udp_listener.py +149 -0
- pyatomberg-0.1.0/pyatomberg/lock/__init__.py +39 -0
- pyatomberg-0.1.0/pyatomberg/lock/cloud_sync.py +165 -0
- pyatomberg-0.1.0/pyatomberg/lock/dynamic_pin.py +216 -0
- pyatomberg-0.1.0/pyatomberg/lock/hsj_protocol.py +287 -0
- pyatomberg-0.1.0/pyatomberg/lock/pairing.py +193 -0
- pyatomberg-0.1.0/pyatomberg/models/__init__.py +17 -0
- pyatomberg-0.1.0/pyatomberg/models/device.py +62 -0
- pyatomberg-0.1.0/pyproject.toml +48 -0
- pyatomberg-0.1.0/tests/test_auth.py +60 -0
- pyatomberg-0.1.0/tests/test_client.py +109 -0
- pyatomberg-0.1.0/tests/test_crypto.py +53 -0
- pyatomberg-0.1.0/tests/test_dynamic_pin.py +177 -0
- pyatomberg-0.1.0/tests/test_hsj_protocol.py +132 -0
- pyatomberg-0.1.0/tests/test_pairing.py +37 -0
- pyatomberg-0.1.0/tests/test_udp_listener.py +37 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test Python ${{ matrix.python-version }}
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
cache: pip
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install -e ".[dev]"
|
|
30
|
+
|
|
31
|
+
- name: Run unit tests with pytest
|
|
32
|
+
run: |
|
|
33
|
+
pytest tests/ -v
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
pypi-publish:
|
|
9
|
+
name: Upload release to PyPI
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment:
|
|
12
|
+
name: pypi
|
|
13
|
+
url: https://pypi.org/p/pyatomberg
|
|
14
|
+
permissions:
|
|
15
|
+
id-token: write
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.11"
|
|
25
|
+
|
|
26
|
+
- name: Install build tool
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install build
|
|
30
|
+
|
|
31
|
+
- name: Build distribution packages
|
|
32
|
+
run: |
|
|
33
|
+
python -m build
|
|
34
|
+
|
|
35
|
+
- name: Publish package distributions to PyPI
|
|
36
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
env/
|
|
26
|
+
venv/
|
|
27
|
+
ENV/
|
|
28
|
+
|
|
29
|
+
# Testing & Coverage
|
|
30
|
+
.pytest_cache/
|
|
31
|
+
.coverage
|
|
32
|
+
htmlcov/
|
|
33
|
+
.tox/
|
|
34
|
+
.nox/
|
|
35
|
+
|
|
36
|
+
# IDE & OS
|
|
37
|
+
.vscode/
|
|
38
|
+
.idea/
|
|
39
|
+
*.swp
|
|
40
|
+
*.swo
|
|
41
|
+
*~
|
|
42
|
+
.DS_Store
|
|
43
|
+
Thumbs.db
|
|
44
|
+
|
|
45
|
+
# Secrets & local env
|
|
46
|
+
.env
|
|
47
|
+
*.local.json
|
|
48
|
+
live_tokens.json
|
|
49
|
+
*oauth*.json
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Project Handover: Atomberg IoT Python Library & Integration (`atomberg-py`)
|
|
2
|
+
|
|
3
|
+
This document serves as the primary technical context, reverse-engineered protocol reference, and architectural briefing for any developer or AI coding agent working on the `atomberg-py` repository and its companion Home Assistant custom integration.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [1. Executive Summary & Project Scope](#1-executive-summary--project-scope)
|
|
10
|
+
- [2. Reverse-Engineering Dossier (`com.atomberg.app` v7.7.2)](#2-reverse-engineering-dossier-comatombergapp-v772)
|
|
11
|
+
- [3. Smart Fans Protocol & Architecture](#3-smart-fans-protocol--architecture)
|
|
12
|
+
- [4. Smart Locks Protocol: Haosj (HSJ) BLE](#4-smart-locks-protocol-haosj-hsj-ble)
|
|
13
|
+
- [5. Smart Locks Protocol: Gecko / Sitana Wi-Fi](#5-smart-locks-protocol-gecko--sitana-wi-fi)
|
|
14
|
+
- [6. Extended Device Models: Purifiers & Cooktops](#6-extended-device-models-purifiers--cooktops)
|
|
15
|
+
- [7. Hardware Provenance & Ecosystem Analysis](#7-hardware-provenance--ecosystem-analysis)
|
|
16
|
+
- [8. Target Library Architecture (`pyatomberg`)](#8-target-library-architecture-pyatomberg)
|
|
17
|
+
- [9. Hardware Resumption Checklist & Action Plan](#9-hardware-resumption-checklist--action-plan)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Executive Summary & Project Scope
|
|
22
|
+
|
|
23
|
+
* **Repository Goal**: Build a unified, standalone Python library (`pyatomberg`) and subsequent Home Assistant custom integration (`atomberg`) supporting Atomberg's ecosystem of smart home devices.
|
|
24
|
+
* **Target Devices**:
|
|
25
|
+
1. **Smart BLDC Ceiling Fans**: Renesa, Renesa+, Aris, Erica, Studio+ (Cloud REST + Local Subnet UDP 5625).
|
|
26
|
+
2. **Smart Door Locks**:
|
|
27
|
+
- **SL1 / SL1 Pro**: Offline Bluetooth Low Energy (BLE) control via Haosj (HSJ) protocol with AES-128 encryption.
|
|
28
|
+
- **SL1.0 / Azhero Series**: Wi-Fi enabled mortise lock using Silicon Labs Wireless Gecko + Firebase Firestore.
|
|
29
|
+
3. **Smart Water Purifiers**: W-Series / W4 (TDS sensors, filter life, tank levels, UV/RO state).
|
|
30
|
+
4. **Smart Cooktops**: Induction cooktop models (Power, heat levels, timer, child lock).
|
|
31
|
+
* **Architecture Philosophy**: Local-first wherever possible. Fans use real-time local UDP broadcast listening (port 5625) to eliminate cloud polling latency; locks communicate via direct local Bluetooth Low Energy (`bleak`). Cloud APIs are utilized for initial discovery, token issuance, and non-local fan commands.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 2. Reverse-Engineering Dossier (`com.atomberg.app` v7.7.2)
|
|
36
|
+
|
|
37
|
+
The official Atomberg Home Android application (`com.atomberg.app` v7.7.2, build 263) was decompiled and analyzed from native assembly (`libapp.so`).
|
|
38
|
+
|
|
39
|
+
### A. Application Stack & AWS Authentication
|
|
40
|
+
* **Framework**: Flutter / Dart compiled into ARMv7/ARM64 shared libraries (`libapp.so`).
|
|
41
|
+
* **Authentication Provider**: AWS Amplify + AWS Cognito Identity Provider.
|
|
42
|
+
- **Cognito User Pool ID**: `ap-south-1_fMZyKIlR2`
|
|
43
|
+
- **App Client ID**: `3cr9rf3urr1jvpn46fsd377uv0`
|
|
44
|
+
- **AWS Region**: `ap-south-1` (Mumbai, India)
|
|
45
|
+
- **OAuth Web Domain**: `auth.atomberg-iot.com`
|
|
46
|
+
* **Local Mobile Persistence**: Hive DB (`TypeAdapter`s for `SitanaLock`, `LockKey`, `GeckoLock`, `AtomDevice`).
|
|
47
|
+
|
|
48
|
+
### B. Core Cloud Endpoints (`server.atomberg-iot.com`)
|
|
49
|
+
All authenticated mobile app requests communicate with the primary API cluster:
|
|
50
|
+
|
|
51
|
+
| Endpoint | Method | Purpose |
|
|
52
|
+
| :--- | :---: | :--- |
|
|
53
|
+
| `https://server.atomberg-iot.com/app_open` | `POST` | Core discovery: returns full device tree (`Fan`, `Lock`, `WaterPurifier`, `Cooktop`, `AtomFamily`) |
|
|
54
|
+
| `https://server.atomberg-iot.com/app_open/guest` | `POST` | Unauthenticated discovery mode (fans only; locks explicitly barred) |
|
|
55
|
+
| `https://server.atomberg-iot.com/update_device_state/lock` | `POST` | Syncs lock registration metadata and parameters |
|
|
56
|
+
| `https://server.atomberg-iot.com/update_device_state/lockhistory` | `POST` | Uploads/syncs hardware audit log events |
|
|
57
|
+
| `https://server.atomberg-iot.com/update_device_state/sitanakey/add` | `POST` | Registers new PIN, NFC, or Fingerprint credential in cloud |
|
|
58
|
+
| `https://server.atomberg-iot.com/update_device_state/sitanakey/modify` | `POST` | Modifies credential attributes (name, validity, schedule) |
|
|
59
|
+
| `https://server.atomberg-iot.com/update_device_state/sitanakey/delete` | `POST` | Revokes credential from cloud inventory |
|
|
60
|
+
| `https://server.atomberg-iot.com/update_device_state/sitanaunlock/decision` | `POST` | Confirms remote unlock request approval/rejection |
|
|
61
|
+
| `https://server.atomberg-iot.com/update_device_state/lockcommands` | `POST` | Dispatches pending remote commands to Wi-Fi locks |
|
|
62
|
+
| `https://server.atomberg-iot.com/update_device_state/w4_state_update` | `POST` | Telemetry sync for W4 water purifiers |
|
|
63
|
+
| `https://server.atomberg-iot.com/send_mqtt_to_device` | `POST` | Cloud relay to dispatch MQTT packets to fans/devices |
|
|
64
|
+
| `https://server.atomberg-iot.com/lrp/get_dynamic_password` | `POST` | Generates time-synchronized offline keypad OTPs |
|
|
65
|
+
| `wss://server.atomberg-iot.com` | `WSS` | WebSocket stream for live mobile client state sync |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 3. Smart Fans Protocol & Architecture
|
|
70
|
+
|
|
71
|
+
Atomberg smart ceiling fans operate using a hybrid **Cloud Command + Local Subnet Telemetry** architecture.
|
|
72
|
+
|
|
73
|
+
### A. Official Developer API (`api.developer.atomberg-iot.com`)
|
|
74
|
+
* **Portal**: `https://developer.atomberg-iot.com`
|
|
75
|
+
* **In-App Activation**: In `com.atomberg.app`, opening `DeveloperOptionsScreen` (`pages/developer_options.dart`) calls:
|
|
76
|
+
`POST https://acw6qw6wsd.execute-api.ap-south-1.amazonaws.com/dev/get_developer_refresh_token`
|
|
77
|
+
*Requirement: At least one Wi-Fi connected fan must be associated with the account.*
|
|
78
|
+
* **Endpoints**:
|
|
79
|
+
- `POST /v1/get_access_token`: Exchanging developer `refresh_token` for bearer JWT `access_token`.
|
|
80
|
+
- `GET /v1/get_all_devices`: Retrieves registered fans, models, series, and online status.
|
|
81
|
+
- `POST /v1/send_command`: Dispatches fan controls:
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"device_id": "ab_fan_xxxxxxxxxxxx",
|
|
85
|
+
"command": {
|
|
86
|
+
"power": true,
|
|
87
|
+
"speed": 5,
|
|
88
|
+
"sleep": false,
|
|
89
|
+
"timer_hours": 0,
|
|
90
|
+
"light_mode": "daylight",
|
|
91
|
+
"led": 80
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### B. Real-Time Local UDP Broadcast (Port 5625)
|
|
97
|
+
* **Mechanics**: Each Wi-Fi canopy module broadcasts unencrypted UDP state datagrams to the local network broadcast address (`255.255.255.255:5625`).
|
|
98
|
+
* **Frame Structure**: Uses HAProxy-style text prefixing:
|
|
99
|
+
```text
|
|
100
|
+
PROXY TCP4 <device_local_ip> <gateway_ip> <src_port> <dst_port>\r\n
|
|
101
|
+
{"device_id":"ab_fan_xxx","power":1,"speed":4,"sleep":0,"timer":0,"last_seen":1728723456}
|
|
102
|
+
```
|
|
103
|
+
* **Integration Strategy**: `pyatomberg` runs an async `UDPListener` on port 5625. When state packets arrive, the library updates the device entity immediately, providing zero-latency state synchronization without querying cloud servers.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 4. Smart Locks Protocol: Haosj (HSJ) BLE
|
|
108
|
+
|
|
109
|
+
Tested on **Atomberg SL1 / SL1 Pro Smart Door Lock**.
|
|
110
|
+
|
|
111
|
+
### A. BLE GATT Profile
|
|
112
|
+
* **Primary Service UUID**: `0000fff0-0000-1000-8000-00805f9b34fb`
|
|
113
|
+
* **Write Characteristic UUID**: `0000fff1-0000-1000-8000-00805f9b34fb` (Write / Write without response)
|
|
114
|
+
* **Notify Characteristic UUID**: `0000fff2-0000-1000-8000-00805f9b34fb` (Notifications enabled)
|
|
115
|
+
|
|
116
|
+
### B. Cryptographic Specifications
|
|
117
|
+
* **Cipher**: AES-128 in ECB mode (`AES.MODE_ECB`).
|
|
118
|
+
* **Padding**: Standard PKCS#7 (16-byte blocks).
|
|
119
|
+
* **Checksum**: Modbus CRC-16 (Polynomial `0xA001`, Initial `0xFFFF`, Little-Endian byte order in protocol).
|
|
120
|
+
* **Hardcoded Factory Key**:
|
|
121
|
+
```python
|
|
122
|
+
FACTORY_KEY = b"mQ3cJOATdERLW1a5" # 16-byte ASCII
|
|
123
|
+
```
|
|
124
|
+
* **Pairing Credentials**:
|
|
125
|
+
- `STATIC_MASTER_KEY`: 16-byte shared secret generated/exchanged during pairing.
|
|
126
|
+
- `LOCK_SALT`: 4-byte salt (8-character hex, e.g. `1a2b3c4d`).
|
|
127
|
+
|
|
128
|
+
### C. Frame Construction & Decoding
|
|
129
|
+
* **Frame Header**: ASCII `HSJ` (`0x48 0x53 0x4A`).
|
|
130
|
+
* **Plaintext Frame Format**:
|
|
131
|
+
`[HSJ Header (3B)] + [Cmd ID (2B)] + [Length (2B)] + [Payload (NB)] + [CRC16 (2B)]`
|
|
132
|
+
* **Encrypted Transmission**: Payload sections are encrypted using `STATIC_MASTER_KEY` (or `FACTORY_KEY` during unbonded pairing).
|
|
133
|
+
|
|
134
|
+
### D. Key Event Categories (Cmd ID `0x000A`)
|
|
135
|
+
* **Category `0x04`**: Unlocked Successfully
|
|
136
|
+
- Credential Types: `0x01` Fingerprint, `0x02` PIN Code, `0x04` NFC Card, `0x00` App Remote.
|
|
137
|
+
- Includes user ID slot and timestamp.
|
|
138
|
+
* **Category `0x36`**: Access Denied / Tamper Warning
|
|
139
|
+
- Credential Types: Unregistered fingerprint, wrong keypad PIN, unauthorized NFC card.
|
|
140
|
+
- Captures bad PIN ASCII strings entered on keypad.
|
|
141
|
+
* **Category `0x3D`**: Auto-Lock / Latch Engaged
|
|
142
|
+
- Signals automatic bolt engagement after unlock window expires (default: 5 seconds).
|
|
143
|
+
|
|
144
|
+
### E. Pairing & Key Extraction Options
|
|
145
|
+
1. **Direct Native BLE Pairing (Zero-Snoop)**:
|
|
146
|
+
Because `FACTORY_KEY` is known, `pyatomberg` can connect to a factory-reset lock, execute the initial pairing frame sequence, write a new random `STATIC_MASTER_KEY` and `LOCK_SALT`, and store them in Home Assistant config entries without Android Developer Options or ADB.
|
|
147
|
+
2. **BTSnoop Parser Fallback**:
|
|
148
|
+
For locks already paired to the official Atomberg app, `pyatomberg.lock.pairing` provides an automated parser that scans `btsnoop_hci.log` (from `adb bugreport`), isolates GATT writes on `0xFFF1`, decrypts the handshake with `FACTORY_KEY`, and extracts `STATIC_MASTER_KEY` and `LOCK_SALT`.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 5. Smart Locks Protocol: Gecko / Sitana Wi-Fi
|
|
153
|
+
|
|
154
|
+
Applies to **Atomberg SL1.0 / Azhero Series** smart mortise locks.
|
|
155
|
+
|
|
156
|
+
* **Architecture**: Combines onboard Wi-Fi (2.4 GHz) with Bluetooth Low Energy.
|
|
157
|
+
* **Chipset**: Silicon Labs Wireless Gecko (EFR32 SoC).
|
|
158
|
+
* **Wi-Fi Provisioning**: BLE strategy (`SitanaProvisionStrategy` / `SitanaChangeWifiUseCase`) passes home SSID and WPA2 passphrase to the lock.
|
|
159
|
+
* **Cloud Architecture**:
|
|
160
|
+
- Primary Database: Google Firebase Firestore (`GeckoLock.fromFirestore`).
|
|
161
|
+
- Event Flow: Visitor interaction creates a `sitana_unlock_request` document in Firestore.
|
|
162
|
+
- Mobile App Hook: Fires push notification to `SitanaUnlockSheet`.
|
|
163
|
+
- Cloud Decision: Owner approval dispatches command via `POST /update_device_state/sitanaunlock/decision` queued into `/update_device_state/lockcommands`.
|
|
164
|
+
* **Offline LRP Passwords**: For offline scenarios, the lock calculates dynamic OTPs based on shared counter/time algorithms (`/lrp/get_dynamic_password`).
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 6. Extended Device Models: Purifiers & Cooktops
|
|
169
|
+
|
|
170
|
+
Atomberg's unified cloud payload (`/app_open`) includes telemetry models for other household appliances:
|
|
171
|
+
|
|
172
|
+
### A. Smart Water Purifiers (W-Series / W4)
|
|
173
|
+
* **Model Identifiers**: `tanker40V2`, `w4_state_update`.
|
|
174
|
+
* **Available Telemetry**:
|
|
175
|
+
- `input_tds` (PPM): Raw incoming water quality.
|
|
176
|
+
- `output_tds` (PPM): Drinking water quality.
|
|
177
|
+
- `filter_life` (%): Health percentages for Pre-Filter, Carbon Filter, RO Membrane, Post-Carbon Filter.
|
|
178
|
+
- `tank_status`: `tank_empty`, `tank_filling`, `tank_full`.
|
|
179
|
+
- `purification_mode`: `ro_mode`, `uv_mode`, `ro_cleaning`, `flushing`.
|
|
180
|
+
- `water_consumed_liters` & `water_saved_liters`.
|
|
181
|
+
|
|
182
|
+
### B. Smart Induction Cooktops
|
|
183
|
+
* **Model Identifier**: `Cooktop.fromAppOpen`.
|
|
184
|
+
* **Available Controls & Telemetry**:
|
|
185
|
+
- `power`: Binary on/off state.
|
|
186
|
+
- `heat_level`: Wattage/temperature stages.
|
|
187
|
+
- `timer`: Remaining cook countdown.
|
|
188
|
+
- `child_lock`: Front-panel lockout toggle.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 7. Hardware Provenance & Ecosystem Analysis
|
|
193
|
+
|
|
194
|
+
* **Lock Hardware (SL1 / SL1 Pro)**:
|
|
195
|
+
- **OEM**: **Fujian Haosj Electronic Science & Technology Co., Ltd. (HSJiao)**, Fujian, China.
|
|
196
|
+
- **Distinction**: Not TTLock (Sciener) and not Tuya. Uses Haosj’s proprietary fixed-key AES-128 protocol.
|
|
197
|
+
* **Lock Hardware (Wi-Fi Azhero)**:
|
|
198
|
+
- **SoC**: Silicon Labs Wireless Gecko (EFR32).
|
|
199
|
+
* **Fan Hardware**:
|
|
200
|
+
- **Motor**: In-house BLDC motor designed and manufactured by Atomberg in India.
|
|
201
|
+
- **IoT Module**: Espressif ESP32 / Beken Wi-Fi microcontroller running custom "Phoenix" firmware with local UDP broadcasting.
|
|
202
|
+
* **Ecosystem Synergy vs. Qubo/TTLock**:
|
|
203
|
+
- Atomberg's AWS Mumbai backend (`ap-south-1`) delivers lower latency for Indian users compared to TTLock's overseas servers.
|
|
204
|
+
- Combining Atomberg fans and locks under `pyatomberg` provides a single unified library for Home Assistant instead of fragmented vendor plugins.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 8. Target Library Architecture (`pyatomberg`)
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
atomberg-py/
|
|
212
|
+
├── pyatomberg/
|
|
213
|
+
│ ├── __init__.py # Package entry point
|
|
214
|
+
│ ├── const.py # Protocol UUIDs, factory keys, endpoints, UDP port 5625
|
|
215
|
+
│ ├── exceptions.py # Authentication, BLE, and connection exception classes
|
|
216
|
+
│ ├── client.py # AtombergClient (Cognito auth, /app_open device loader)
|
|
217
|
+
│ ├── crypto.py # AES-128-ECB and Modbus CRC-16 routines
|
|
218
|
+
│ ├── fan/
|
|
219
|
+
│ │ ├── __init__.py
|
|
220
|
+
│ │ ├── device.py # AtombergFan: speed (1-6), power, timer, LED, sleep
|
|
221
|
+
│ │ └── udp_listener.py # Async UDP socket listener on port 5625
|
|
222
|
+
│ ├── lock/
|
|
223
|
+
│ │ ├── __init__.py
|
|
224
|
+
│ │ ├── device.py # AtombergLock: Bleak BLE client
|
|
225
|
+
│ │ ├── hsj_protocol.py # Haosj frame builder, parser, access log decoder
|
|
226
|
+
│ │ ├── pairing.py # Native BLE pairing handshake tool & BTSnoop parser
|
|
227
|
+
│ │ └── models.py # Lock events, credentials (NFC/PIN/fingerprint), battery
|
|
228
|
+
│ ├── purifier/
|
|
229
|
+
│ │ ├── __init__.py
|
|
230
|
+
│ │ └── device.py # AtombergWaterPurifier: TDS, filter life, tank level
|
|
231
|
+
│ ├── cooktop/
|
|
232
|
+
│ │ ├── __init__.py
|
|
233
|
+
│ │ └── device.py # AtombergCooktop: power, timer, temperature presets
|
|
234
|
+
│ ├── models/
|
|
235
|
+
│ │ ├── base.py
|
|
236
|
+
│ │ └── device.py # Unified device dataclasses from fromAppOpen
|
|
237
|
+
│ └── cli.py # Command-line interface for testing and pairing
|
|
238
|
+
├── tests/
|
|
239
|
+
│ ├── test_crypto.py # Validates AES-128 and Modbus CRC-16 against known test vectors
|
|
240
|
+
│ ├── test_hsj_protocol.py # Validates frame creation and notification decoding
|
|
241
|
+
│ └── test_udp_listener.py # Validates PROXY TCP4 datagram parsing
|
|
242
|
+
├── pyproject.toml # Poetry/Build configuration (bleak, cryptography, aiohttp)
|
|
243
|
+
├── README.md # Installation, CLI documentation, and HA integration guide
|
|
244
|
+
└── HANDOVER.md # This document
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 9. Hardware Resumption Checklist & Action Plan
|
|
250
|
+
|
|
251
|
+
When the physical smart fans and door lock are delivered and installed:
|
|
252
|
+
|
|
253
|
+
### Phase 1: Environment & Repository Setup
|
|
254
|
+
- [ ] Initialize git repository in `D:\GitHub\atomberg-py`.
|
|
255
|
+
- [ ] Install dependencies in local virtualenv (`bleak`, `cryptography`, `aiohttp`, `pydantic`, `pytest`).
|
|
256
|
+
|
|
257
|
+
### Phase 2: Cryptography & Framing Verification
|
|
258
|
+
- [ ] Implement `pyatomberg/crypto.py` (AES-128-ECB and Modbus CRC-16).
|
|
259
|
+
- [ ] Run test suite with known test vectors from `dreadedlama/atomberg-lock` and APK dumps.
|
|
260
|
+
|
|
261
|
+
### Phase 3: Live Fan Integration (Cloud + Local UDP)
|
|
262
|
+
- [ ] Pair fans to home Wi-Fi via official Atomberg app.
|
|
263
|
+
- [ ] Activate Developer Mode in app settings to obtain developer `refresh_token` and `api_key`.
|
|
264
|
+
- [ ] Test `api.developer.atomberg-iot.com` REST client in `pyatomberg/fan/device.py`.
|
|
265
|
+
- [ ] Run `UDPListener` on port 5625 and verify incoming `PROXY TCP4` packets while toggling fan speeds.
|
|
266
|
+
|
|
267
|
+
### Phase 4: Live Lock Integration (BLE / Haosj)
|
|
268
|
+
- [ ] Place lock in BLE pairing mode or capture initial pairing handshake.
|
|
269
|
+
- [ ] Validate lock MAC, `STATIC_MASTER_KEY`, and `LOCK_SALT` generation.
|
|
270
|
+
- [ ] Verify local unlock command over BLE characteristic `0xFFF1`.
|
|
271
|
+
- [ ] Verify notification stream on `0xFFF2` (live battery status and audit log events).
|
|
272
|
+
|
|
273
|
+
### Phase 5: Home Assistant Custom Integration Packaging
|
|
274
|
+
- [ ] Scaffold `custom_components/atomberg` consuming `pyatomberg`.
|
|
275
|
+
- [ ] Implement `fan.py` with 6 speeds, sleep toggle, timer, and local UDP coordinator.
|
|
276
|
+
- [ ] Implement `lock.py` using Home Assistant's `bluetooth` component (`async_ble_device_from_address`).
|
|
277
|
+
- [ ] Add sensors for battery level, last unlock credential type, and last user.
|