Open Modderhut opened 3 weeks ago
pin code is exchanged when the device is "paired" by default 4cad343a-209a-40b7-b911-4d9b3df569b2 reads 00 00 00 00 but in pairing mode is is exchanged and never changes.
Add me (eriknn84) on discord and I’ll help!
Are there any updates? I'm not on Discord but happy to help. I've got some ideas on how to implement something more generic.
@Modderhut Were you able to get the existing integration to work with the pin code? I followed these instructions, but it didn't seem to work for me.
It looks like it might be quite different compared to the Pax. I think we have two options here:
Anyways, someone has to figure out these id’s and what the data types are, and that has to be someone that has this fan. Or it might be extracted from an apk-file.
Option 1 would be the easiest, but option 2 would be the nicest IMO.
If Pax/Vent-Axia are consistent with CHARACTERISTIC_DEVICE_NAME
then we can use that to load in a different list for each model. I think it's available without pairing which helps, but as some models have the PIN on the unit and other during the pairing process it may as well be a manual drop down to select the model name.
I'll see what I can get working, but at the moment I can't even pair to the device.
Hi @RobPope thanks! all help is welcome! Discord is free and a sort of chat env. You can install it and just search for our usernames if you want.
I have been working on it but have a hard time deciphering the python code as I'm not a coder.
I'm using Bluetooth LE Lab from the windows store on my pc and that connects fine to the fan and I can read all characteristics and their return value's.
Using JADX I've decompiled "Vent-Axia Connect_6.1.72_APKPure.apk", as the app is for multiple fan types its hard to find the right code.
x-referencing the Eriks code with what I find in BLE and finding the meaning of that characteristic in the apk I have now below characteristics that are in the BLE explorer. When I change these in Erik's code the HA plugin fails to load, so working my way trough by commenting out stuff. I'm also trying to setup PyCharm to do this outside HA as the reloads are really slowing me down. Again not a coder so very slow at this.
The pin is exchanged during pairing and is not found on the device 4cad343a-209a-40b7-b911-4d9b3df569b2 reads 00 00 00 00 but when pairing mode is enabled it reads a value. As far as I tested the pin is static and does not change. Not sure but I think if you take the output in decimals and fill that as pincode is works to pair. Don't think the pin is need for reading but only needed for writing values.
sensor_data reads hex 00 00 C0 05 35 04 00 00 00 00 39 04 00 15 00
I guess these are sensor readings combined, I'm also trying to figure out how @eriknn deciphered these in his code.
The fan only allows 1 connection so kill BLE explorer or phone app when trying HA
CHARACTERISTIC_DEVICE_NAME = "00002a00-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_APPEARANCE = "00002a01-0000-1000-8000-00805f9b34fb"
CHARACTERISTIC_MODEL_NUMBER = "00002A24-0000-1000-8000-00805F9B34FB" CHARACTERISTIC_HARDWARE_REVISION = "00002A27-0000-1000-8000-00805F9B34FB" CHARACTERISTIC_FIRMWARE_REVISION = "00002A26-0000-1000-8000-00805F9B34FB" CHARACTERISTIC_SOFTWARE_REVISION = "00002A28-0000-1000-8000-00805F9B34FB" CHARACTERISTIC_MANUFACTURER_NAME = "00002A29-0000-1000-8000-00805F9B34FB" CHARACTERISTIC_PIN_CODE = "4CAD343A-209A-40B7-B911-4D9B3DF569B2" CHARACTERISTIC_PIN_CONFIRMATION = "D1AE6B70-EE12-4F6D-B166-D2063DCAFFE1" CHARACTERISTIC_FAN_DESCRIPTION = "B85FA07A-9382-4838-871C-81D045DCC2FF" CHARACTERISTIC_BLE_ADDRESS = "638ff62c-3823-4e0f-8179-1695c46ee8af" #NEW CHARACTERISTIC_STATUS = "25A824AD-3021-4DE9-9F2F-60CF8D17BDED" CHARACTERISTIC_SENSOR_DATA = "528B80E8-C47A-4C0A-BDF1-916A7748F412" CHARACTERISTIC_FACTORY_SETTINGS_CHANGED = "7C4ADC01-2F33-11E7-93AE-92361F002671" CHARACTERISTIC_PRESENCE_GAS = "7c4adc02-2f33-11e7-93ae-92361f002671" #NEW CHARACTERISTIC_CONSTANT_OPERATION = "7C4ADC03-2F33-11E7-93AE-92361F002671" #NEW CHARACTERISTIC_TIME_FUNCTIONS = "7c4adc04-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_AUTOMATIC_CYCLES = "7c4adc05-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_PAUSE = "7c4adc06-2f33-11e7-93ae-92361f002671" #NEW CHARACTERISTIC_BOOST = "7c4adc07-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_FAN_TEST = "7c4adc08-2f33-11e7-93ae-92361f002671" #NEW
CHARACTERISTIC_BASIC_VENTILATION = "faa49e09-a79c-4725-b197-bdc57c67dc32" #in eriknn's code but not in BLE CHARACTERISTIC_CLOCK = "6dec478e-ae0b-4186-9d82-13dda03c0682" #in eriknn's code but not in BLE CHARACTERISTIC_LED = "8b850c04-dc18-44d2-9501-7662d65ba36e" #in eriknn's code but not in BLE CHARACTERISTIC_MODE = "7c4adc0d-2f33-11e7-93ae-92361f002671" #in eriknn's code but not in BLE CHARACTERISTIC_MODEL_NAME = "00002a00-0000-1000-8000-00805f9b34fb" #in eriknn's code but not in BLE CHARACTERISTIC_NIGHT_MODE = "b5836b55-57bd-433e-8480-46e4993c5ac0" #in eriknn's code but not in BLE CHARACTERISTIC_RESET = "ff5f7c4f-2606-4c69-b360-15aaea58ad5f" #in eriknn's code but not in BLE CHARACTERISTIC_SERIAL_NUMBER = "00002a25-0000-1000-8000-00805f9b34fb" #in eriknn's code but not in BLE CHARACTERISTIC_TEMP_HEAT_DISTRIBUTOR = "a22eae12-dba8-49f3-9c69-1721dcff1d96" #in eriknn's code but not in BLE
7C4ADC09-2F33-11E7-93AE-92361F002671 in BLE investigation but not found anywhere else 7C4ADC0A-2F33-11E7-93AE-92361F002671 in BLE investigation but not found anywhere else 7C4ADC0B-2F33-11E7-93AE-92361F002671 in BLE investigation but not found anywhere else 7C4ADC0C-2F33-11E7-93AE-92361F002671 in BLE investigation but not found anywhere else 7C4ADC0D-2F33-11E7-93AE-92361F002671 in BLE investigation but not found anywhere else 7C4ADC0E-2F33-11E7-93AE-92361F002671 in BLE investigation but not found anywhere else
The format of sensor data could be was found in the pax apk (This wasn't my work). Probably the same for other fan types. You see this part in calima.py:
async def getState(self) -> FanState:
# Short Short Short Short Byte Short Byte
# Hum Temp Light FanSpeed Mode Tbd Tbd
v = unpack("<4HBHB", await self._readUUID(CHARACTERISTIC_SENSOR_DATA))
Which matches the following in the Pax Apk:
@Override // com.volution.wrapper.acdeviceconnection.request.BaseRequest
public Observable<CalimaResponseSensorData> execute() {
if (getConnection() == null) {
return Observable.error(new Exception("Connection was null"));
}
return getConnection().read(getData()).map(new Func1<byte[], CalimaResponseSensorData>() { // from class: com.volution.wrapper.acdeviceconnection.request.CalimaRequestSensorDataRead.1
@Override // rx.functions.Func1
public CalimaResponseSensorData call(byte[] bArr) {
ByteBuffer order = ByteBuffer.wrap(bArr).order(ByteOrder.LITTLE_ENDIAN);
CalimaResponseSensorData calimaResponseSensorData = new CalimaResponseSensorData();
calimaResponseSensorData.setHumidityLevel(order.getShort(0));
calimaResponseSensorData.setTemperature(order.getShort(2));
calimaResponseSensorData.setLightLevel(order.getShort(4));
calimaResponseSensorData.setFanSpeed(order.getShort(6));
calimaResponseSensorData.setCurrentTrigger(order.get(8));
calimaResponseSensorData.setTbd(order.get(9));
return calimaResponseSensorData;
}
});
}
Further finding scaling / meaning of the values might require testing.
The fan only allows 1 connection so kill BLE explorer or phone app when trying HA
This is true, and really sucks. It's why this integration always connects and disconnects for each read, so that it is possible to use the phone as well. I was thinking about making this a configuration option, so that you could keep a permanent connection. Not sure if that was ever implemented.
I've installed BLE Lab on my laptop and it's giving me the same output as I had on GATTBrowser from my phone, but with values I can copy and paste out. Not sure when I'll have a chance to take a deep dive into it, but will update you on progress. Have you got a branch with the code you've been working on so far @Modderhut? Or are you working locally only at the moment?
I can take a look at refactoring this integration tonight, to allow for different fan types. I believe there already is a connection made when adding the device, so I’ll look into reading device name/type there, and we’ll take it from there. I might release a beta version for you guys to test.
I've installed BLE Lab on my laptop and it's giving me the same output as I had on GATTBrowser from my phone, but with values I can copy and paste out. Not sure when I'll have a chance to take a deep dive into it, but will update you on progress. Have you got a branch with the code you've been working on so far @Modderhut? Or are you working locally only at the moment?
created a fork but that's not practical till we get somewhere, till now its just research and I'm editing directly into the custom integration in HA with Notepad++
I can take a look at refactoring this integration tonight, to allow for different fan types. I believe there already is a connection made when adding the device, so I’ll look into reading device name/type there, and we’ll take it from there. I might release a beta version for you guys to test.
uuid 00001800-0000-1000-8000-00805F9B34FB char 00002A00-0000-1000-8000-00805F9B34FB CHARACTERISTIC_DEVICE_NAME
outputs 83 118 101 110 115 97 UTF8 "Svensa" which is the model name, as its read-only I guess it would be a good ID
I created a framework with model selection in the configuration, that's all I have time for now. Would be nice if you guys can builld on this and figure out if it'll work. Each device model name has its own class containing the characteristics. I predict we'll have to move some of the functions there as well.
Edit: So the flow is like this at the moment: HASS -> Coordinator -> BleFan -> Device(BaseDevice)
I'm pretty sure we could move the functions in BleFan to the BaseDevice class, and instantiate the specific device model in the coordinator. This way the specific variants could override whichever functions are not "standard".
Edit2: I don't have a fan at the moment, so I'm only able to see that I don't get any errors when start HASS, and trying to add a device.
I had a look last night and think I've found the first issue. Are you getting any values from CHARACTERISTIC_SENSOR_DATA
@Modderhut?
I wrote the following code to take the value from that GUID and parse it through the function only to be met with a failure because it was expecting 12 bytes. The sensor data on mine appears to be 15 bytes.
sensorData = bytearray.fromhex("10 00 6D 07 E9 04 08 00 00 00 51 04 00 18 00")
byteData = bytearray(sensorData)
print(struct.calcsize("<4HBHB")) # <- Gives the value of 12
print(len(byteData)) # <- Gives the value of 15
The output doesn't quite align with the values I was expecting so I think the format needs updating, I just need to do some research into how. It might need some unpacking of the APK to know for sure
I found this in the APK
@Override // com.volution.wrapper.acdeviceconnection.request.BaseRequest public Observable<SkyDeviceSensor> execute() { if (getConnection() == null) { return Observable.error(new Exception("Connection was null")); } return getConnection().read(getData()).map(new Func1<byte[], SkyDeviceSensor>() { // from class: com.volution.wrapper.acdeviceconnection.request.SkyDeviceRequestSensorDataRead.1 @Override // rx.functions.Func1 public SkyDeviceSensor call(byte[] bArr) { ByteBuffer order = ByteBuffer.wrap(bArr).order(ByteOrder.LITTLE_ENDIAN); SkyDeviceSensor skyDeviceSensor = new SkyDeviceSensor(); skyDeviceSensor.setTrigger1(order.get(0)); skyDeviceSensor.setTrigger2(order.get(1)); skyDeviceSensor.setHumidityLvl(order.getShort(2)); skyDeviceSensor.setGasLvl(order.getShort(4)); skyDeviceSensor.setLightLvl(order.getShort(6)); skyDeviceSensor.setFanSpeed(order.getShort(8)); return skyDeviceSensor; } }); }
when I translate that to python I get
class SkyDeviceRequestSensorDataRead: def execute(self): connection = self.get_connection() if connection is None: return Observable.error(Exception("Connection was null")) return connection.read(self.get_data()).map(lambda b_arr: self.parse_sensor_data(b_arr)) def parse_sensor_data(self, b_arr): order = struct.unpack('<BBHHHHH', b_arr) # Little-endian format sky_device_sensor = SkyDeviceSensor() sky_device_sensor.set_trigger1(order[0]) sky_device_sensor.set_trigger2(order[1]) sky_device_sensor.set_humidity_lvl(order[2]) sky_device_sensor.set_gas_lvl(order[3]) sky_device_sensor.set_light_lvl(order[4]) sky_device_sensor.set_fan_speed(order[5]) return sky_device_sensor
I have what is probably an old Pax apk lying here, and in this it seems that Sky may be a different fan? Maybe Fresh Intellivent Sky? I have a feeling that there are a lot of fans out there using roughly the same software / app... Guess we'll have to add them all in the end.
These are probably the different reported names:
public static final String DEVICE_NAME_AIR_SENSE = "Air Sense";
public static final String DEVICE_NAME_AVIANT = "Aviant";
public static final String DEVICE_NAME_CALIMA = "Calima";
public static final String DEVICE_NAME_COMAIR_HRUC_PLUS = "Comair HRUC-Plus";
public static final String DEVICE_NAME_CONTROLLER = "Controller";
public static final String DEVICE_NAME_DMVHR = "SmartVent fresh dMVHR";
public static final String DEVICE_NAME_E16 = "SmartVent fresh e16";
public static final String DEVICE_NAME_EASY_CONNECT_E_16 = "Easy Connect e16";
public static final String DEVICE_NAME_FCU = "FCU";
public static final String DEVICE_NAME_FCX_90 = "FCX 90";
public static final String DEVICE_NAME_FLOW = "Flow";
public static final String DEVICE_NAME_FLOW_KONTROLLPANEL = "Flow Kontrollpannel";
public static final String DEVICE_NAME_HYPER = "Hyper";
public static final String DEVICE_NAME_INTELLIVENT_ICE = "Intellivent ICE";
public static final String DEVICE_NAME_INTELLIVENT_SKY = "Intellivent SKY";
public static final String DEVICE_NAME_IV_CONNECT = "ivConnect";
public static final String DEVICE_NAME_KINETIC = "Kinetic";
public static final String DEVICE_NAME_LEVANTE = "Levante 50";
public static final String DEVICE_NAME_MANROSE_GENIUS = "Manrose Genius";
public static final String DEVICE_NAME_MANROSE_QUIET = "Manrose Quiet";
public static final String DEVICE_NAME_MEV = "MEV";
public static final String DEVICE_NAME_MEV_COMAIR_DELTA = "Comair Delta";
public static final String DEVICE_NAME_MEV_MULTIHOME = "Multihome";
public static final String DEVICE_NAME_MOMENTO = "Momento";
public static final String DEVICE_NAME_MZCU = "MZCU";
public static final String DEVICE_NAME_PAX_LEVANTE = "Pax Levante";
public static final String DEVICE_NAME_PAX_MOMENTO = "Pax Momento";
public static final String DEVICE_NAME_PULSAR = "Pulsar";
public static final String DEVICE_NAME_PURE_AIR_SENSE = "PureAir Sense";
public static final String DEVICE_NAME_PURE_SENSE = "Pure Sense";
public static final String DEVICE_NAME_SKY = "Sky";
public static final String DEVICE_NAME_SVARA = "Svara";
public static final String DEVICE_NAME_SVENSA = "Svensa";
public static final String DEVICE_NAME_VENT_AXIA_SVARA = "Vent-Axia Svara";
public static final String DEVICE_NAME_ZCU = "ZCU";
public static final String FLAVOR_COMAIR = "comair";
public static final String FLAVOR_FRESH = "fresh";
public static final String FLAVOR_INVENTER = "inventer";
public static final String FLAVOR_MANROSE = "manrose";
public static final String FLAVOR_PAX = "pax";
public static final String FLAVOR_SIMX = "simx";
public static final String FLAVOR_VENTAXIA = "ventaxia";
public static final int PRODUCT_CALIMA = 0;
public static final int PRODUCT_HYPER = 7;
public static final int PRODUCT_KINETIC = 2;
public static final int PRODUCT_LEVANTE = 9;
public static final int PRODUCT_MEV = 6;
public static final int PRODUCT_MOMENTO = 5;
public static final int PRODUCT_SKY = 1;
public static final int PRODUCT_XFL_PRO = 8;
public static final int PRODUCT_ZIRCONIA_FCU = 3;
public static final int PRODUCT_ZIRCONIA_MZCU = 4;
Further, this probably hints at which fans use the same firmware(?):
public static int getImageForProduct(String str) {
str.hashCode();
char c = 65535;
switch (str.hashCode()) {
case -2012406216:
if (str.equals(Constants.DEVICE_NAME_COMAIR_HRUC_PLUS)) {
c = 0;
break;
}
break;
case -1985561074:
if (str.equals(Constants.DEVICE_NAME_MANROSE_GENIUS)) {
c = 1;
break;
}
break;
case -1893252195:
if (str.equals(Constants.DEVICE_NAME_PULSAR)) {
c = 2;
break;
}
break;
case -1846639247:
if (str.equals(Constants.DEVICE_NAME_FLOW_KONTROLLPANEL)) {
c = 3;
break;
}
break;
case -1806654022:
if (str.equals(Constants.DEVICE_NAME_SVENSA)) {
c = 4;
break;
}
break;
case -1664073796:
if (str.equals(Constants.DEVICE_NAME_CONTROLLER)) {
c = 5;
break;
}
break;
case -1395042737:
if (str.equals(Constants.DEVICE_NAME_MOMENTO)) {
c = 6;
break;
}
break;
case -1273321984:
if (str.equals(Constants.DEVICE_NAME_LEVANTE)) {
c = 7;
break;
}
break;
case -963503872:
if (str.equals(Constants.DEVICE_NAME_PURE_AIR_SENSE)) {
c = '\b';
break;
}
break;
case -884209162:
if (str.equals(Constants.DEVICE_NAME_EASY_CONNECT_E_16)) {
c = '\t';
break;
}
break;
case -638922444:
if (str.equals(Constants.DEVICE_NAME_VENT_AXIA_SVARA)) {
c = '\n';
break;
}
break;
case -85654462:
if (str.equals(Constants.DEVICE_NAME_PAX_LEVANTE)) {
c = 11;
break;
}
break;
case 69432:
if (str.equals(Constants.DEVICE_NAME_FCU)) {
c = '\f';
break;
}
break;
case 76222:
if (str.equals(Constants.DEVICE_NAME_MEV)) {
c = '\r';
break;
}
break;
case 83201:
if (str.equals(Constants.DEVICE_NAME_SKY)) {
c = 14;
break;
}
break;
case 88652:
if (str.equals(Constants.DEVICE_NAME_ZCU)) {
c = 15;
break;
}
break;
case 2192718:
if (str.equals(Constants.DEVICE_NAME_FLOW)) {
c = 16;
break;
}
break;
case 2382559:
if (str.equals(Constants.DEVICE_NAME_MZCU)) {
c = 17;
break;
}
break;
case 70209100:
if (str.equals(Constants.DEVICE_NAME_HYPER)) {
c = 18;
break;
}
break;
case 80264429:
if (str.equals(Constants.DEVICE_NAME_SVARA)) {
c = 19;
break;
}
break;
case 154342979:
if (str.equals(Constants.DEVICE_NAME_DMVHR)) {
c = 20;
break;
}
break;
case 178143512:
if (str.equals(Constants.DEVICE_NAME_AIR_SENSE)) {
c = 21;
break;
}
break;
case 675654913:
if (str.equals(Constants.DEVICE_NAME_MEV_COMAIR_DELTA)) {
c = 22;
break;
}
break;
case 797615480:
if (str.equals(Constants.DEVICE_NAME_MEV_MULTIHOME)) {
c = 23;
break;
}
break;
case 954071225:
if (str.equals(Constants.DEVICE_NAME_KINETIC)) {
c = 24;
break;
}
break;
case 1079948214:
if (str.equals(Constants.DEVICE_NAME_PAX_MOMENTO)) {
c = 25;
break;
}
break;
case 1305036541:
if (str.equals(Constants.DEVICE_NAME_IV_CONNECT)) {
c = 26;
break;
}
break;
case 1658259382:
if (str.equals(Constants.DEVICE_NAME_E16)) {
c = 27;
break;
}
break;
case 1973095091:
if (str.equals(Constants.DEVICE_NAME_AVIANT)) {
c = 28;
break;
}
break;
case 1991358598:
if (str.equals(Constants.DEVICE_NAME_PURE_SENSE)) {
c = 29;
break;
}
break;
case 2011056463:
if (str.equals(Constants.DEVICE_NAME_CALIMA)) {
c = 30;
break;
}
break;
case 2023866557:
if (str.equals(Constants.DEVICE_NAME_MANROSE_QUIET)) {
c = 31;
break;
}
break;
case 2068570652:
if (str.equals(Constants.DEVICE_NAME_FCX_90)) {
c = ' ';
break;
}
break;
}
switch (c) {
case 0:
case 24:
case ' ':
return getImageResourceForKinetic();
case 1:
case 2:
case 7:
case '\n':
case 11:
case 19:
case 30:
return getImageResourceForSvara();
case 3:
case 5:
case '\t':
case 15:
case 17:
case 27:
return getImageResourceForZirconia();
case 4:
case '\b':
case 14:
case 21:
case 28:
case 29:
return getImageResourceForSky();
case 6:
case 25:
return getImageResourceForMomento();
case '\f':
case 16:
case 20:
case 26:
return getImageResourceForZirconiaFCU();
case '\r':
case 22:
case 23:
return getImageResourceForMev();
case 18:
return getImageResourceForHyper();
case 31:
getImageResourceForManrose();
break;
}
return getImageResourceForSvara();
}
The format "<BBHHHHH" isn't correct for the response I'm getting for fan state as it's still 12 bytes. I hate working with byte arrays and shifting bits, so this is going to take a lot of trial and error.
I've managed to log the outputs with the format "<4BBHHHHH" into the HA debug log, but it's still not looking obvious where to go from here. I'm going to guess v[1] is the mode and v[6] is the fan speed.
No fan: Read Fan States: (0, 0, 205, 4, 77, 5, 0, 22528, 5, 24) Boost fan: Read Fan States: (0, 103, 9, 4, 53, 5, 32512, 12553, 5, 24)
I've created a discord channel to continue there
Dear Eriknn
Like @texnic in closed issue #49 I'm trying to add my Svensa fan to HA. I've decompiled a android package and interrogated the device using BLE Inspector but my coding skills are not good enough to solve this.
Would you be willing to assist? I can do any testing needed.
I have matched characteristics from BLE explorer with decompiles apk and made changes to calima.py;
CHARACTERISTIC_APPEARANCE = "00002a01-0000-1000-8000-00805f9b34fb"
CHARACTERISTIC_AUTOMATIC_CYCLES = "f508408a-508b-41c6-aa57-61d1fd0d5c39"
CHARACTERISTIC_AUTOMATIC_CYCLES = "7c4adc05-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_BASIC_VENTILATION = "faa49e09-a79c-4725-b197-bdc57c67dc32"
CHARACTERISTIC_BOOST = "118c949c-28c8-4139-b0b3-36657fd055a9"
CHARACTERISTIC_BOOST = "7c4adc07-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_CLOCK = "6dec478e-ae0b-4186-9d82-13dda03c0682" CHARACTERISTIC_DEVICE_NAME = "00002a00-0000-1000-8000-00805f9b34fb"
CHARACTERISTIC_FACTORY_SETTINGS_CHANGED = "63b04af9-24c0-4e5d-a69c-94eb9c5707b4"
CHARACTERISTIC_FACTORY_SETTINGS_CHANGED = "7c4adc01-2f33-11e7-93ae-92361f002671" #same as humidity? CHARACTERISTIC_FAN_DESCRIPTION = "b85fa07a-9382-4838-871c-81d045dcc2ff" CHARACTERISTIC_FIRMWARE_REVISION = "00002a26-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_HARDWARE_REVISION = "00002a27-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_SOFTWARE_REVISION = "00002a28-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_LED = "8b850c04-dc18-44d2-9501-7662d65ba36e" CHARACTERISTIC_LEVEL_OF_FAN_SPEED = "1488a757-35bc-4ec8-9a6b-9ecf1502778e"
CHARACTERISTIC_MANUFACTURER_NAME = "00002a29-0000-1000-8000-00805f9b34fb"
CHARACTERISTIC_MANUFACTURER_NAME = "90ED66FE-8854-C433-A290-B96C5C8D418D"
CHARACTERISTIC_MODE = "90cabcd1-bcda-4167-85d8-16dcd8ab6a6b"
CHARACTERISTIC_MODE = "7c4adc0d-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_MODEL_NAME = "00002a00-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_MODEL_NUMBER = "00002a24-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_NIGHT_MODE = "b5836b55-57bd-433e-8480-46e4993c5ac0" CHARACTERISTIC_PIN_CODE = "4cad343a-209a-40b7-b911-4d9b3df569b2" CHARACTERISTIC_PIN_CONFIRMATION = "d1ae6b70-ee12-4f6d-b166-d2063dcaffe1" CHARACTERISTIC_RESET = "ff5f7c4f-2606-4c69-b360-15aaea58ad5f" CHARACTERISTIC_SENSITIVITY = "e782e131-6ce1-4191-a8db-f4304d7610f1" CHARACTERISTIC_SENSOR_DATA = "528b80e8-c47a-4c0a-bdf1-916a7748f412" CHARACTERISTIC_SERIAL_NUMBER = "00002a25-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_SOFTWARE_REVISION = "00002a28-0000-1000-8000-00805f9b34fb" CHARACTERISTIC_STATUS = "25a824ad-3021-4de9-9f2f-60cf8d17bded" CHARACTERISTIC_TEMP_HEAT_DISTRIBUTOR = "a22eae12-dba8-49f3-9c69-1721dcff1d96" CHARACTERISTIC_TIME_FUNCTIONS = "49c616de-02b1-4b67-b237-90f66793a6f2"
New Values
CHARACTERISTIC_CONSTANT_OPERATION = "7c4adc03-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_BLE_ADDRESS = "638ff62c-3823-4e0f-8179-1695c46ee8af" CHARACTERISTIC_HUMIDITY = "7c4adc01-2f33-11e7-93ae-92361f002671" # same as FACTORY_SETTINGS_CHANGED?? CHARACTERISTIC_FAN_TEST = "7c4adc08-2f33-11e7-93ae-92361f002671" HARACTERISTIC_PAUSE = "7c4adc06-2f33-11e7-93ae-92361f002671" CHARACTERISTIC_PRESENCE_GAS = "7c4adc02-2f33-11e7-93ae-92361f002671"