Genesis
This commit is contained in:
348
API_REFERENCE.md
Normal file
348
API_REFERENCE.md
Normal file
@@ -0,0 +1,348 @@
|
||||
# AC Infinity API Reference
|
||||
|
||||
This document provides technical details about the AC Infinity API integration used by this Homebridge plugin. It covers the API endpoints, payload formats, and controller-specific approaches discovered through reverse engineering.
|
||||
|
||||
## API Base URL
|
||||
|
||||
```
|
||||
http://www.acinfinityserver.com
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
The API uses simple token-based authentication:
|
||||
|
||||
1. Login with email/password to get a user token
|
||||
2. Include token in subsequent requests via the `token` header
|
||||
|
||||
### Login Request
|
||||
|
||||
```http
|
||||
POST /api/user/appUserLogin
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
appEmail=user@example.com&appPasswordl=password123
|
||||
```
|
||||
|
||||
**Note**: The API parameter is `appPasswordl` (with 'l') - this is intentional and matches the official API.
|
||||
|
||||
**Password Limitation**: API only accepts first 25 characters of password.
|
||||
|
||||
### Login Response
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "success.",
|
||||
"code": 200,
|
||||
"data": {
|
||||
"appId": "1234567890123456789",
|
||||
"nickName": "user@example.com",
|
||||
"appEmail": "user@example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `appId` is used as the authentication token for subsequent requests.
|
||||
|
||||
## Core Endpoints
|
||||
|
||||
### Get Device List
|
||||
|
||||
```http
|
||||
POST /api/user/devInfoListAll
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
userId=1234567890123456789
|
||||
```
|
||||
|
||||
Headers:
|
||||
```
|
||||
token: 1234567890123456789
|
||||
phoneType: 1
|
||||
appVersion: 1.9.7
|
||||
```
|
||||
|
||||
### Get Device Mode Settings
|
||||
|
||||
```http
|
||||
POST /api/dev/getdevModeSettingList
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
devId=1234567890123456789&port=2
|
||||
```
|
||||
|
||||
Headers:
|
||||
```
|
||||
token: 1234567890123456789
|
||||
phoneType: 1
|
||||
appVersion: 1.9.7
|
||||
minversion: 3.5
|
||||
```
|
||||
|
||||
### Set Device Mode (Fan Control)
|
||||
|
||||
```http
|
||||
POST /api/dev/addDevMode
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
[See Controller-Specific Payloads below]
|
||||
```
|
||||
|
||||
## Device Types
|
||||
|
||||
AC Infinity manufactures different types of devices:
|
||||
|
||||
### Supported: Controller-Based Devices
|
||||
|
||||
These devices have a central controller with USB-C ports for connecting fans and sensors:
|
||||
|
||||
#### UIS 89 AI+ (Type 20)
|
||||
- **Device Type**: 20
|
||||
- **newFrameworkDevice**: true
|
||||
- **API Approach**: Hardcoded static payload
|
||||
- **User-Agent**: `ACController/1.9.7 (com.acinfinity.humiture; build:533; iOS 18.5.0) Alamofire/5.10.2`
|
||||
|
||||
#### UIS 69 PRO (Type 11)
|
||||
- **Device Type**: 11
|
||||
- **newFrameworkDevice**: false
|
||||
- **API Approach**: Static payload with real device settings
|
||||
- **User-Agent**: `ACController/1.9.7 (com.acinfinity.humiture; build:533; iOS 18.5.0) Alamofire/5.10.2`
|
||||
|
||||
#### UIS 69 PRO+ (Type 18)
|
||||
- **Device Type**: 18
|
||||
- **newFrameworkDevice**: false
|
||||
- **API Approach**: Static payload with real device settings
|
||||
- **User-Agent**: `ACController/1.9.7 (com.acinfinity.humiture; build:533; iOS 18.5.0) Alamofire/5.10.2`
|
||||
|
||||
### Unsupported: Standalone Devices
|
||||
|
||||
**Airtap T4/T6 Register Booster Fans** - These standalone Wi-Fi devices don't have a controller or ports structure. The API likely returns device data without the `deviceInfo.ports` array.
|
||||
|
||||
**Status**: Not yet supported. Need device data from actual Airtap users to implement support.
|
||||
|
||||
**Workaround**: Use [ESP32 module replacement](https://silocitylabs.com/post/2025/esp32-airtap-esphome/) for ESPHome/Home Assistant integration.
|
||||
|
||||
## Controller-Specific Payloads
|
||||
|
||||
### UIS 89 AI+ (Hardcoded Static Payload)
|
||||
|
||||
For newer controllers, use a static payload with hardcoded values:
|
||||
|
||||
```http
|
||||
POST /api/dev/addDevMode
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
acitveTimerOff=0&acitveTimerOn=0&activeCycleOff=0&activeCycleOn=0&activeHh=0&activeHt=0&activeHtVpd=0&activeHtVpdNums=0&activeLh=0&activeLt=0&activeLtVpd=0&activeLtVpdNums=0&atType=2&co2FanHighSwitch=0&co2FanHighValue=0&co2LowSwitch=0&co2LowValue=0&devHh=0&devHt=0&devHtf=32&devId=1234567890123456789&devLh=0&devLt=0&devLtf=32&devMacAddr=&ecOrTds=0&ecTdsLowSwitchEc=0&ecTdsLowSwitchTds=0&ecTdsLowValueEcMs=1&ecTdsLowValueEcUs=0&ecTdsLowValueTdsPpm=0&ecTdsLowValueTdsPpt=1&ecUnit=0&externalPort=1&hTrend=0&humidity=0&isOpenAutomation=0&masterPort=0&modeType=2&moistureLowSwitch=0&moistureLowValue=0&offSpead=0&onSelfSpead=7&onSpead=7&onlyUpdateSpeed=0&phHighSwitch=0&phHighValue=0&phLowSwitch=0&phLowValue=0&schedEndtTime=65535&schedStartTime=65535&settingMode=0&speak=0&surplus=0&tTrend=0&targetHumi=0&targetHumiSwitch=0&targetTSwitch=0&targetTemp=0&targetTempF=32&targetVpd=0&targetVpdSwitch=0&tdsUnit=0&temperature=0&temperatureF=0&trend=0&unit=0&vpdSettingMode=0&waterLevelLowSwitch=0&waterTempHighSwitch=0&waterTempHighValue=0&waterTempHighValueF=32&waterTempLowSwitch=0&waterTempLowValue=0&waterTempLowValueF=32
|
||||
```
|
||||
|
||||
**Key Parameters**:
|
||||
- `onSpead=7`: Target fan speed (0-10)
|
||||
- `modeType=2`: Set to ON mode (use `0` to turn off)
|
||||
- `externalPort=1`: Port number
|
||||
|
||||
Headers:
|
||||
```
|
||||
token: 1234567890123456789
|
||||
phoneType: 1
|
||||
appVersion: 1.9.7
|
||||
minversion: 3.5
|
||||
```
|
||||
|
||||
### UIS 69 PRO (Static Payload with Real Settings)
|
||||
|
||||
For older controllers, first fetch current settings, then send them in static payload format:
|
||||
|
||||
1. **Fetch Current Settings** (as shown above)
|
||||
|
||||
2. **Send Static Payload** with real values:
|
||||
|
||||
```http
|
||||
POST /api/dev/addDevMode
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
acitveTimerOff=[REAL_VALUE]&acitveTimerOn=[REAL_VALUE]&activeCycleOff=[REAL_VALUE]&...&onSpead=7&...
|
||||
```
|
||||
|
||||
Headers:
|
||||
```
|
||||
token: 1234567890123456789
|
||||
phoneType: 1
|
||||
appVersion: 1.9.7
|
||||
```
|
||||
|
||||
**Critical Differences**:
|
||||
- Populate payload with actual device settings (not zeros)
|
||||
- **Omit the `modeSetid` field** (this causes 403 errors)
|
||||
- Set `modeType=2` when `onSpead > 0` to activate the fan (or `modeType=0` to turn off)
|
||||
- Only change the `onSpead` and `modeType` parameters
|
||||
- Keep all other values as retrieved from current settings
|
||||
|
||||
## Key API Fields
|
||||
|
||||
### Fan Speed Control
|
||||
- **onSpead**: Target fan speed (0-10)
|
||||
- **speak**: Current fan power level (0-10, read-only)
|
||||
- **onSelfSpead**: Self-regulating speed setting
|
||||
|
||||
### Device Information
|
||||
- **devId**: Device identifier
|
||||
- **externalPort**: Port number (1-8 depending on controller)
|
||||
- **devType**: Controller type (11=UIS 69 PRO, 20=UIS 89 AI+, 18=UIS 69 PRO+)
|
||||
- **newFrameworkDevice**: Boolean indicating API approach needed
|
||||
|
||||
### Environmental Data
|
||||
- **temperature**: Temperature (×100, e.g., 2366 = 23.66°C)
|
||||
- **humidity**: Humidity (×100, e.g., 5118 = 51.18%)
|
||||
- **vpdnums**: VPD value (×100, e.g., 143 = 1.43 kPa)
|
||||
|
||||
### Mode Detection
|
||||
- **curMode**: Current operating mode (read-only status)
|
||||
- `1` = OFF
|
||||
- `2` = ON (Manual)
|
||||
- `3` = AUTO
|
||||
- `8` = VPD
|
||||
- **modeType**: Mode to set when changing settings
|
||||
- `0` = OFF
|
||||
- `2` = ON (Manual)
|
||||
- **Important**: Must set `modeType=2` when changing speed to activate the fan
|
||||
|
||||
### Port Status
|
||||
- **online**: Port connection status (0/1)
|
||||
- **loadState**: Load detection (0/1)
|
||||
- **portResistance**: Port resistance reading
|
||||
|
||||
## Error Codes
|
||||
|
||||
- **200**: Success
|
||||
- **403**: "Data saving failed" (rate limiting or invalid payload)
|
||||
- **404**: Endpoint not found
|
||||
- **500**: Invalid credentials
|
||||
- **10001**: Authentication failed
|
||||
- **100001**: Generic request error
|
||||
- **999999**: Operation failed (usually unsupported controller)
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Speed Changes Not Persisting
|
||||
|
||||
**Symptom**: API returns 200 success, but controller doesn't change speed. Speed reverts to 0 after a few seconds.
|
||||
|
||||
**Root Cause**: Controller is in OFF mode (`curMode: 1`). The API accepts speed changes but the controller ignores them when not activated.
|
||||
|
||||
**Solution**: Always set `modeType=2` (ON) when setting `onSpead > 0`. Set `modeType=0` when turning off.
|
||||
|
||||
**Example**:
|
||||
```
|
||||
// Wrong - speed won't persist if controller is OFF
|
||||
onSpead=5&modeType=0
|
||||
|
||||
// Correct - activates controller and sets speed
|
||||
onSpead=5&modeType=2
|
||||
|
||||
// Correct - turns off controller
|
||||
onSpead=0&modeType=0
|
||||
```
|
||||
|
||||
### "Data saving failed" (403)
|
||||
|
||||
**Symptom**: 403 error when trying to set fan speed on UIS 69 PRO.
|
||||
|
||||
**Root Cause**: Including `modeSetid` field or using wrong payload format.
|
||||
|
||||
**Solution**:
|
||||
- For UIS 69 PRO: Use static payload with real device settings (NO `modeSetid`)
|
||||
- For UIS 89 AI+: Use hardcoded static payload
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
The API implements connection-based rate limiting:
|
||||
- Multiple requests from different connections are treated as different clients
|
||||
- Use persistent HTTP connections (keepalive) to avoid rate limits
|
||||
- Implement request queuing with reasonable delays (500ms between requests)
|
||||
|
||||
## Network Analysis
|
||||
|
||||
This API documentation was created through:
|
||||
|
||||
1. **Charles Proxy Analysis**: Captured official AC Infinity iPhone app network traffic
|
||||
2. **Home Assistant Integration**: Analyzed working Home Assistant plugin implementation
|
||||
3. **Live Testing**: Tested with actual UIS 69 PRO and UIS 89 AI+ hardware
|
||||
4. **Reverse Engineering**: Discovered controller-specific approaches through trial and error
|
||||
|
||||
## Security Notes
|
||||
|
||||
⚠️ **Important Security Considerations**:
|
||||
|
||||
- API credentials (email/password) are transmitted in plain text
|
||||
- Authentication tokens have no visible expiration
|
||||
- All API communication happens over HTTP (not HTTPS)
|
||||
- This API is intended for local network use with AC Infinity controllers
|
||||
- Never expose API credentials in public repositories or logs
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### HTTP Client Configuration
|
||||
|
||||
```javascript
|
||||
const axios = axios.create({
|
||||
baseURL: 'http://www.acinfinityserver.com',
|
||||
timeout: 15000,
|
||||
headers: {
|
||||
'User-Agent': 'ACController/1.9.7 (com.acinfinity.humiture; build:533; iOS 18.5.0) Alamofire/5.10.2',
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
||||
},
|
||||
httpAgent: new Agent({ keepAlive: true, maxSockets: 1 }),
|
||||
httpsAgent: new HttpsAgent({ keepAlive: true, maxSockets: 1 }),
|
||||
maxRedirects: 3,
|
||||
validateStatus: (status) => status < 500,
|
||||
});
|
||||
```
|
||||
|
||||
### Controller Detection
|
||||
|
||||
```javascript
|
||||
function isNewFrameworkDevice(deviceType, deviceData) {
|
||||
// AI+ controllers use hardcoded static payload
|
||||
if (deviceType === 20) return true;
|
||||
|
||||
// Check explicit framework flag
|
||||
if (deviceData?.newFrameworkDevice === true) return true;
|
||||
if (deviceData?.newFrameworkDevice === false) return false;
|
||||
|
||||
// Default: older controllers use real settings approach
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```javascript
|
||||
if (response.data.code === 403) {
|
||||
// Rate limited or invalid payload
|
||||
// For UIS 69 PRO: try iPhone app approach
|
||||
// For UIS 89 AI+: verify static payload format
|
||||
}
|
||||
|
||||
if (response.data.code === 999999) {
|
||||
// Unsupported controller or wrong API approach
|
||||
// Switch between hardcoded vs real settings method
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
A comprehensive test CLI application is included (`test-api.js`) that:
|
||||
- Auto-detects controller types
|
||||
- Uses appropriate API approach for each controller
|
||||
- Includes fallback logic for unknown devices
|
||||
- Provides detailed logging for debugging
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
node test-api.js http://www.acinfinityserver.com email@example.com password123 devices
|
||||
node test-api.js http://www.acinfinityserver.com email@example.com password123 speed DEVICE_ID PORT_ID SPEED
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*This documentation reflects the current understanding of the AC Infinity API as of December 2025. The API may change without notice as it's not officially documented by AC Infinity.*
|
||||
Reference in New Issue
Block a user