esp32_ethernet_milight_hub/lib/MiLight/CctPacketFormatter.cpp

226 lines
5.8 KiB
C++

#include <CctPacketFormatter.h>
#include <MiLightCommands.h>
static const uint8_t CCT_PROTOCOL_ID = 0x5A;
bool CctPacketFormatter::canHandle(const uint8_t *packet, const size_t len) {
return len == packetLength && packet[0] == CCT_PROTOCOL_ID;
}
void CctPacketFormatter::initializePacket(uint8_t* packet) {
size_t packetPtr = 0;
// Byte 0: Packet length = 7 bytes
// Byte 1: CCT protocol
packet[packetPtr++] = CCT_PROTOCOL_ID;
// Byte 2 and 3: Device ID
packet[packetPtr++] = deviceId >> 8;
packet[packetPtr++] = deviceId & 0xFF;
// Byte 4: Zone
packet[packetPtr++] = groupId;
// Byte 5: Bulb command, filled in later
packet[packetPtr++] = 0;
// Byte 6: Packet sequence number 0..255
packet[packetPtr++] = sequenceNum++;
// Byte 7: Checksum over previous bytes, including packet length = 7
// The checksum will be calculated when setting the command field
packet[packetPtr++] = 0;
// Byte 8: CRC LSB
// Byte 9: CRC MSB
}
void CctPacketFormatter::finalizePacket(uint8_t* packet) {
uint8_t checksum;
// Calculate checksum over packet length .. sequenceNum
checksum = 7; // Packet length is not part of packet
for (uint8_t i = 0; i < 6; i++) {
checksum += currentPacket[i];
}
// Store the checksum in the sixth byte
currentPacket[6] = checksum;
}
void CctPacketFormatter::updateBrightness(uint8_t value) {
const GroupState* state = this->stateStore->get(deviceId, groupId, MiLightRemoteType::REMOTE_TYPE_CCT);
int8_t knownValue = (state != NULL && state->isSetBrightness()) ? state->getBrightness() / CCT_INTERVALS : -1;
valueByStepFunction(
&PacketFormatter::increaseBrightness,
&PacketFormatter::decreaseBrightness,
CCT_INTERVALS,
value / CCT_INTERVALS,
knownValue
);
}
void CctPacketFormatter::updateTemperature(uint8_t value) {
const GroupState* state = this->stateStore->get(deviceId, groupId, MiLightRemoteType::REMOTE_TYPE_CCT);
int8_t knownValue = (state != NULL && state->isSetKelvin()) ? state->getKelvin() / CCT_INTERVALS : -1;
valueByStepFunction(
&PacketFormatter::increaseTemperature,
&PacketFormatter::decreaseTemperature,
CCT_INTERVALS,
value / CCT_INTERVALS,
knownValue
);
}
void CctPacketFormatter::command(uint8_t command, uint8_t arg) {
pushPacket();
if (held) {
command |= 0x80;
}
currentPacket[CCT_COMMAND_INDEX] = command;
}
void CctPacketFormatter::updateStatus(MiLightStatus status, uint8_t groupId) {
command(getCctStatusButton(groupId, status), 0);
}
void CctPacketFormatter::increaseTemperature() {
command(CCT_TEMPERATURE_UP, 0);
}
void CctPacketFormatter::decreaseTemperature() {
command(CCT_TEMPERATURE_DOWN, 0);
}
void CctPacketFormatter::increaseBrightness() {
command(CCT_BRIGHTNESS_UP, 0);
}
void CctPacketFormatter::decreaseBrightness() {
command(CCT_BRIGHTNESS_DOWN, 0);
}
void CctPacketFormatter::enableNightMode() {
command(getCctStatusButton(groupId, OFF) | 0x10, 0);
}
uint8_t CctPacketFormatter::getCctStatusButton(uint8_t groupId, MiLightStatus status) {
uint8_t button = 0;
if (status == ON) {
switch(groupId) {
case 0:
button = CCT_ALL_ON;
break;
case 1:
button = CCT_GROUP_1_ON;
break;
case 2:
button = CCT_GROUP_2_ON;
break;
case 3:
button = CCT_GROUP_3_ON;
break;
case 4:
button = CCT_GROUP_4_ON;
break;
}
} else {
switch(groupId) {
case 0:
button = CCT_ALL_OFF;
break;
case 1:
button = CCT_GROUP_1_OFF;
break;
case 2:
button = CCT_GROUP_2_OFF;
break;
case 3:
button = CCT_GROUP_3_OFF;
break;
case 4:
button = CCT_GROUP_4_OFF;
break;
}
}
return button;
}
uint8_t CctPacketFormatter::cctCommandIdToGroup(uint8_t command) {
switch (command & 0xF) {
case CCT_GROUP_1_ON:
case CCT_GROUP_1_OFF:
return 1;
case CCT_GROUP_2_ON:
case CCT_GROUP_2_OFF:
return 2;
case CCT_GROUP_3_ON:
case CCT_GROUP_3_OFF:
return 3;
case CCT_GROUP_4_ON:
case CCT_GROUP_4_OFF:
return 4;
case CCT_ALL_ON:
case CCT_ALL_OFF:
return 0;
}
return 255;
}
MiLightStatus CctPacketFormatter::cctCommandToStatus(uint8_t command) {
switch (command & 0xF) {
case CCT_GROUP_1_ON:
case CCT_GROUP_2_ON:
case CCT_GROUP_3_ON:
case CCT_GROUP_4_ON:
case CCT_ALL_ON:
return ON;
case CCT_GROUP_1_OFF:
case CCT_GROUP_2_OFF:
case CCT_GROUP_3_OFF:
case CCT_GROUP_4_OFF:
case CCT_ALL_OFF:
default:
return OFF;
}
}
BulbId CctPacketFormatter::parsePacket(const uint8_t* packet, JsonObject result) {
uint8_t command = packet[CCT_COMMAND_INDEX] & 0x7F;
uint8_t onOffGroupId = cctCommandIdToGroup(command);
BulbId bulbId(
(packet[1] << 8) | packet[2],
onOffGroupId < 255 ? onOffGroupId : packet[3],
REMOTE_TYPE_CCT
);
// Night mode
if (command & 0x10) {
result[GroupStateFieldNames::COMMAND] = MiLightCommandNames::NIGHT_MODE;
} else if (onOffGroupId < 255) {
result[GroupStateFieldNames::STATE] = cctCommandToStatus(command) == ON ? "ON" : "OFF";
} else if (command == CCT_BRIGHTNESS_DOWN) {
result[GroupStateFieldNames::COMMAND] = "brightness_down";
} else if (command == CCT_BRIGHTNESS_UP) {
result[GroupStateFieldNames::COMMAND] = "brightness_up";
} else if (command == CCT_TEMPERATURE_DOWN) {
result[GroupStateFieldNames::COMMAND] = MiLightCommandNames::TEMPERATURE_DOWN;
} else if (command == CCT_TEMPERATURE_UP) {
result[GroupStateFieldNames::COMMAND] = MiLightCommandNames::TEMPERATURE_UP;
} else {
result["button_id"] = command;
}
return bulbId;
}
void CctPacketFormatter::format(uint8_t const* packet, char* buffer) {
PacketFormatter::formatV1Packet(packet, buffer);
}