Hi there,
I’m trying to monitor and control my Inkbird ISC-007BW BBQ controller via bluetooth.
So far I’ve managed to connect to the device, start reading the temperatures and fan speed, and I’ve been able to control the fan speed by sending commands to it. However, setting the speed needs to perform a write action to the blue_client which is an array of 20 bytes which looks like this:
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x9b, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
The first byte is on (0x01) or off (0x00). The seventh byte is the speed in hex (here 0x0a = 10 %). Now the tricky part is bytes 12 and 13. I found out its a CRC16/MODBUS calculation over the first 11 bytes in hex in reversed order. Is there a way to calculate those bytes in ESPhome? Otherwise im left with creating 100 commands for each percentage setting Perhaps even more once I figure out the rest of the bytes and commands.
I started out in python because I thought I could create a custom component but since I’m not a programmer, that was a bit too hard and switched to ESPhome. In python I made something like this to create the command using a value for switch and speed:
from crccheck.crc import Crc16Modbus
# calculate hex
def crc(data):
crcinst = Crc16Modbus()
crcinst.process(data)
crc = crcinst.finalhex()
return crc[2:4] +" " + crc[0:2] + "00 00 00 00 00 00 00"
def commandfull(switch, speed):
commandshort = bytearray.fromhex( switch + " 00 00 00 00 01 " + '{0:02x}'.format(speed) + " 00 00 00 00 ")
#data = commandshort
crcresult = crc(commandshort)
return commandshort + bytearray.fromhex( crcresult )
command = commandfull("01", 10)
print (command)
This resulted in the above byte array in which I set the fan speed to 10%. The current ESP yaml looks like this: (not completed yet but it works)
esphome:
name: esp32
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
esp32_ble_tracker:
#not used global variable but an example of how to store an array for sending a command
globals:
- id: blecommand
type: std::vector<unsigned char>
initial_value: '{0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}'
ble_client:
- mac_address: 49:22:04:02:00:F8
id: isc007bw
on_connect:
then:
- lambda: |-
ESP_LOGD("ble_client_lambda", "Connected to BLE device");
# created one subscription sensor that publishes all the data to the other sensors since it's all in the same message
sensor:
- platform: ble_client
type: characteristic
ble_client_id: isc007bw
id: fanspeed
name: "Fan Speed"
service_uuid: 'FFF0' # device service
characteristic_uuid: 'FFF6' # subsciption
notify: true
lambda: |-
uint8_t speed = x[6];
uint16_t temp1 = x[0] | x[1] <<8;
id(isc_probe1).publish_state((float)temp1 /10 );
uint16_t temp2 = x[2] | x[3] <<8;
id(isc_probe2).publish_state((float)temp2 /10 );
uint16_t temp3 = x[4] | x[5] <<8;
id(isc_probe3).publish_state((float)temp3 /10 );
return (float)speed ;
unit_of_measurement: '%'
icon: "mdi:fan"
- platform: template
id: isc_probe1
name: "isc probe 1"
device_class: "temperature"
unit_of_measurement: '°F'
- platform: template
id: isc_probe2
name: "isc probe 2"
device_class: "temperature"
unit_of_measurement: '°F'
- platform: template
id: isc_probe3
name: "isc probe 3"
device_class: "temperature"
unit_of_measurement: '°F'
#Output for the fan template. I hardcoded only 3 values but that's what I like to change
output:
- platform: template
id: isc_output
type: float
write_action:
- if:
condition:
fan.is_on: isc_fan
then:
- ble_client.ble_write:
id: isc007bw
service_uuid: FFF0
characteristic_uuid: FFF1
value: !lambda |-
if (id(isc_fan).speed == 1) {return {0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};}
if (id(isc_fan).speed == 2) {return {0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};}
else {return {0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x9b, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};}
# Fan for HA. Currently just 10 speed count for testing but I want it for 100
fan:
- platform: speed
id: isc_fan
output: isc_output
speed_count: 10
name: "ISC-007BW fan"
on_turn_on:
- logger.log: "Fan turned on"
on_turn_off:
- ble_client.ble_write:
id: isc007bw
service_uuid: FFF0
characteristic_uuid: FFF1
# List of bytes to write.
value: [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
- logger.log: "Fan turned off"
on_speed_set:
- logger.log: "Fan speed was changed!"
# dis/enable the active connection to the device
switch:
- platform: ble_client
ble_client_id: isc007bw
name: "ISC-007BW"
id: isc007bwswitch
I hope anybody can help me out on this. I hoped changing the speed could perhaps just update the correct bytes in a global variable called ‘command’ or something and calculate the correct CRC bytes, and then send that command to ble_client.ble_write. Or if somebody can help me out writing a custom component that would also be great. There are ofcourse more commands and values te read (like setting a timer, setting target temperatures etc, but for now the fan control was my main target).