working python code for 69… ill come back to 67 unless someone else figures out last bit on their own…
was able to get 69 to turn on with
import asyncio
from bleak import *
from bleak import BleakClient
from crccheck.crc import Crc16CcittFalse
address = "34:85:18:6a:52:52"
async def main(address):
async with BleakClient(address) as client:
header = bytes.fromhex("a5000008013bb191")
command = bytes.fromhex("00")
params = bytes.fromhex("0310010212010aff01209a")
crcinst = Crc16CcittFalse()
crcinst.process(header)
crcinst.process(command)
crcinst.process(params)
model_number = await client.write_gatt_char("70d51001-2c7f-4e75-ae8a-d758951ce4e0", header + command + params + crcinst.finalbytes())
asyncio.run(main(address))
with this one it allows open command line , progress? maybe lots of errors which slows this code down now (fixed errors, moving onto seeing if i can create a full working code to integrate into home assistant using this as the starting point. By only needing to change single value (command) we can control the speed of the fan.
we can
import asyncio
from bleak import *
from bleak import BleakClient
from crccheck.crc import Crc16CcittFalse
address = "34:85:18:6a:52:52"
async def main(address):
async with BleakClient(address) as client:
aciuni = bytes.fromhex("a5000008013bb191")
header = bytes.fromhex("00031001021201")
command = bytes.fromhex("00")
params = bytes.fromhex("ff01")
crcinst = Crc16CcittFalse()
crcinst.process(header)
crcinst.process(command)
crcinst.process(params)
model_number = await client.write_gatt_char("70d51001-2c7f-4e75-ae8a-d758951ce4e0",aciuni + header + command + params + crcinst.finalbytes())
asyncio.run(main(address))
heres what i have so far
init.py
"""ACI Universal COntroller"""
ACI_UNI.py
import asyncio
from bleak import BleakClient, BleakScanner
from crccheck.crc import Crc16CcittFalse
import logging
WRITE_UUID = "70d51001-2c7f-4e75-ae8a-d758951ce4e0"
LOGGER = logging.getLogger(__name__)
async def discover():
"""Discover Bluetooth LE devices."""
devices = await BleakScanner.discover()
LOGGER.debug("Discovered devices: %s", [{"address": device.address, "name": device.name} for device in devices])
return [device for device in devices if device.name.startswith("4GRDH")]
class ACIInstance:
def __init__(self, mac: str) -> None:
self._mac = mac
self._device = BleakClient(self._mac)
self._is_on = None
self._connected = None
self._speed = None
async def _send(self, data: bytearray):
LOGGER.debug(''.join(format(x, ' 03x') for x in data))
if (not self._connected):
await self.connect()
crcinst = Crc16CcittFalse()
crcinst.process(data)
await self._device.write_gatt_char(WRITE_UUID, data + crcinst.finalbytes())
@property
def mac(self):
return self._mac
@property
def is_on(self):
return self._is_on
@property
def speed(self):
return self._speed
async def set_speed(self, velocity: int):
aciuni = bytes.fromhex("a5000008013bb191")
header = bytes.fromhex("00031001021201")
command = bytes.fromhex(s)([velocity])
params = bytes.fromhex("ff01")
await self._send(aciuni + header + command + params)
self._speed = velocity
async def turn_on(self):
aciuni = bytes.fromhex("a5000008013bb191")
header = bytes.fromhex("00031001021201")
command = bytes.fromhex([velocity])
params = bytes.fromhex("ff01")
await self._send(aciuni + header + command + params)
self._is_on = True
async def turn_off(self):
aciuni = bytes.fromhex("a500000801ee2a49")
header = bytes.fromhex("00031001011101")
command = bytes.fromhex([velocity])
params = bytes.fromhex("ff01")
await self._send(aciuni + header + command + params)
self._is_on = False
async def connect(self):
await self._device.connect(timeout=20)
await asyncio.sleep(1)
self._connected = True
async def disconnect(self):
if self._device.is_connected:
await self._device.disconnect()
fan.py
"""Provides functionality to interact with fans."""
from __future__ import annotations
import logging
from.ACI_Uni import ACIInstance
import voluptuous as vol
from pprint import pformat
import homeassistant.helpers.config_validation as config_validation
from homeassistant.components.fan import ( SERVICE_TOGGLE,SUPPORT_SET_SPEED,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_ON, PLATFORM_SCHEMA)
from homeassistant.const import CONF_NAME , CONT_MAC
from homeassistant.core import homeassistant
from homeassistant.helpers.entity_platform import AddEntitieCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryType
_LOGGER = logging.getLogger("ACI")
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME): cv.string,
vol.Required(CONF_MAC): cv.sring,
})
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None
) -> None:
"""Set up the ACI_Universal fan platform."""
# Add devices
_LOGGER.info(pformat(config))
Fan = {
"name": config[CONF_NAME],
"mac": config[CONF_MAC]
}
add_entities([ACI_UniversalController(Fan)])
from homeassistant.util.percentage import int_states_in_range, ranged_value_to_percentage, percentage_to_ranged_value
SPEED_RANGE = (1, 10)
percentage = ranged_value_to_percentage(SPEED_RANGE, 10)
value_in_range = math.ceil(percentage_to_ranged_value(SPEED_RANGE, 1))
class FanEntity(ToggleEntity):
def turn_on(self, speed: Optional[str] = None, percentage: Optional[int] = None, preset_mode: Optional[str] = None, **kwargs: Any) -> None:
"""Turn on the fan."""
def turn_off(self, **kwargs: Any) -> None:
"""turn the fan off"""
@property
def percentage(self) -> Optional[int]:
"""Return the current speed percentage."""
return ranged_value_to_percentage(SPEED_RANGE, current_speed)
@property
def speed_count(self) -> int:
"""Return the number of speeds the fan supports."""
return int_states_in_range(SPEED_RANGE)
manifest.json
{
"domain": "ACI Universal Controller",
"name": "ACI 69 Controller",
"requirements": ["bleak==0.19.5", "crccheck==1.3.0"],
"iot_class": "assumed_state",
"version": "0.0"
}
id like to be able to call velocity from a slider to be able to adjust fan speed see how that goes
broke original code sent further , you dont have to use it this long way it just shows what its for so far
import asyncio
from bleak import *
from bleak import BleakClient
from crccheck.crc import Crc16CcittFalse
address = "34:85:18:6a:52:52"
async def main(address):
async with BleakClient(address) as client:
aciuni = bytes.fromhex("a5000008013bb191")
header = bytes.fromhex("00031001")
power = bytes.fromhex("0111")
direction = bytes.fromhex("01")
velocity = bytes.fromhex("04")
params = bytes.fromhex("ff01")
crcinst = Crc16CcittFalse()
crcinst.process(header)
crcinst.process(power)
crcinst.process(direction)
crcinst.process(velocity)
crcinst.process(params)
model_number = await client.write_gatt_char("70d51001-2c7f-4e75-ae8a-d758951ce4e0",aciuni + header + power + direction + velocity + params + crcinst.finalbytes())
asyncio.run(main(address))
you can use all the same code but by changing the power to 0212 it will turn on at the velocity value you set. wit knowing you only have to change this value we can easily configure the message sent to the device a bit easier