# 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.*