Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle inconsistency on saturation/temp on v2 types #227

Merged
merged 12 commits into from
Mar 11, 2018
2 changes: 1 addition & 1 deletion lib/MiLight/CctPacketFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ MiLightStatus CctPacketFormatter::cctCommandToStatus(uint8_t command) {
}
}

BulbId CctPacketFormatter::parsePacket(const uint8_t* packet, JsonObject& result, GroupStateStore* stateStore) {
BulbId CctPacketFormatter::parsePacket(const uint8_t* packet, JsonObject& result) {
uint8_t command = packet[CCT_COMMAND_INDEX] & 0x7F;

BulbId bulbId(
Expand Down
2 changes: 1 addition & 1 deletion lib/MiLight/CctPacketFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CctPacketFormatter : public PacketFormatter {
virtual void format(uint8_t const* packet, char* buffer);
virtual void initializePacket(uint8_t* packet);
virtual void finalizePacket(uint8_t* packet);
virtual BulbId parsePacket(const uint8_t* packet, JsonObject& result, GroupStateStore* stateStore);
virtual BulbId parsePacket(const uint8_t* packet, JsonObject& result);

static uint8_t getCctStatusButton(uint8_t groupId, MiLightStatus status);
static uint8_t cctCommandIdToGroup(uint8_t command);
Expand Down
42 changes: 40 additions & 2 deletions lib/MiLight/FUT089PacketFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ void FUT089PacketFormatter::updateBrightness(uint8_t brightness) {
command(FUT089_BRIGHTNESS, brightness);
}

// change the hue (which may also change to color mode).
void FUT089PacketFormatter::updateHue(uint16_t value) {
uint8_t remapped = Units::rescale(value, 255, 360);
updateColorRaw(remapped);
Expand All @@ -27,13 +28,50 @@ void FUT089PacketFormatter::updateColorRaw(uint8_t value) {
command(FUT089_COLOR, FUT089_COLOR_OFFSET + value);
}

// change the temperature (kelvin). Note that temperature and saturation share the same command
// number (7), and they change which they do based on the mode of the lamp (white vs. color mode).
// To make this command work, we need to switch to white mode, make the change, and then flip
// back to the original mode.
void FUT089PacketFormatter::updateTemperature(uint8_t value) {
updateColorWhite();
// look up our current mode
GroupState ourState = this->stateStore->get(this->deviceId, this->groupId, REMOTE_TYPE_FUT089);
BulbMode originalBulbMode = ourState.getBulbMode();

// are we already in white? If not, change to white
if (originalBulbMode != BulbMode::BULB_MODE_WHITE) {
updateColorWhite();
}

// now make the temperature change
command(FUT089_KELVIN, 100 - value);

// and return to our original mode
if ((settings->enableAutomaticModeSwitching) && (originalBulbMode != BulbMode::BULB_MODE_WHITE)) {
switchMode(ourState, originalBulbMode);
}
}

// change the saturation. Note that temperature and saturation share the same command
// number (7), and they change which they do based on the mode of the lamp (white vs. color mode).
// Therefore, if we are not in color mode, we need to switch to color mode, make the change,
// and switch back to the original mode.
void FUT089PacketFormatter::updateSaturation(uint8_t value) {
// look up our current mode
GroupState ourState = this->stateStore->get(this->deviceId, this->groupId, REMOTE_TYPE_FUT089);
BulbMode originalBulbMode = ourState.getBulbMode();

// are we already in color? If not, we need to flip modes
if ((settings->enableAutomaticModeSwitching) && (originalBulbMode != BulbMode::BULB_MODE_COLOR)) {
updateHue(ourState.getHue());
}

// now make the saturation change
command(FUT089_SATURATION, 100 - value);

// and revert back if necessary
if ((settings->enableAutomaticModeSwitching) && (originalBulbMode != BulbMode::BULB_MODE_COLOR)) {
switchMode(ourState, originalBulbMode);
}
}

void FUT089PacketFormatter::updateColorWhite() {
Expand All @@ -45,7 +83,7 @@ void FUT089PacketFormatter::enableNightMode() {
command(FUT089_ON | 0x80, arg);
}

BulbId FUT089PacketFormatter::parsePacket(const uint8_t *packet, JsonObject& result, GroupStateStore* stateStore) {
BulbId FUT089PacketFormatter::parsePacket(const uint8_t *packet, JsonObject& result) {
uint8_t packetCopy[V2_PACKET_LEN];
memcpy(packetCopy, packet, V2_PACKET_LEN);
V2RFEncoding::decodeV2Packet(packetCopy);
Expand Down
8 changes: 4 additions & 4 deletions lib/MiLight/FUT089PacketFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ enum MiLightFUT089Command {
FUT089_COLOR = 0x02,
FUT089_BRIGHTNESS = 0x05,
FUT089_MODE = 0x06,
FUT089_KELVIN = 0x07,
FUT089_SATURATION = 0x07
FUT089_KELVIN = 0x07, // Controls Kelvin when in White mode
FUT089_SATURATION = 0x07 // Controls Saturation when in Color mode
};

enum MiLightFUT089Arguments {
Expand All @@ -24,7 +24,7 @@ enum MiLightFUT089Arguments {
class FUT089PacketFormatter : public V2PacketFormatter {
public:
FUT089PacketFormatter()
: V2PacketFormatter(0x25, 8)
: V2PacketFormatter(0x25, 8) // protocol is 0x25, and there are 8 groups
{ }

virtual void updateBrightness(uint8_t value);
Expand All @@ -39,7 +39,7 @@ class FUT089PacketFormatter : public V2PacketFormatter {
virtual void modeSpeedUp();
virtual void updateMode(uint8_t mode);

virtual BulbId parsePacket(const uint8_t* packet, JsonObject& result, GroupStateStore* stateStore);
virtual BulbId parsePacket(const uint8_t* packet, JsonObject& result);
};

#endif
93 changes: 79 additions & 14 deletions lib/MiLight/MiLightClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@

MiLightClient::MiLightClient(
MiLightRadioFactory* radioFactory,
GroupStateStore& stateStore,
size_t throttleThreshold,
size_t throttleSensitivity,
size_t packetRepeatMinimum
GroupStateStore* stateStore,
Settings* settings
)
: baseResendCount(MILIGHT_DEFAULT_RESEND_COUNT),
currentRadio(NULL),
Expand All @@ -19,10 +17,8 @@ MiLightClient::MiLightClient(
updateBeginHandler(NULL),
updateEndHandler(NULL),
stateStore(stateStore),
lastSend(0),
throttleThreshold(throttleThreshold),
throttleSensitivity(throttleSensitivity),
packetRepeatMinimum(packetRepeatMinimum)
settings(settings),
lastSend(0)
{
radios = new MiLightRadio*[numRadios];

Expand Down Expand Up @@ -82,7 +78,7 @@ void MiLightClient::prepare(const MiLightRemoteConfig* config,
this->currentRemote = config;

if (deviceId >= 0 && groupId >= 0) {
currentRemote->packetFormatter->prepare(deviceId, groupId);
currentRemote->packetFormatter->prepare(deviceId, groupId, stateStore, settings);
}
}

Expand All @@ -96,7 +92,7 @@ void MiLightClient::prepare(const MiLightRemoteType type,
void MiLightClient::setResendCount(const unsigned int resendCount) {
this->baseResendCount = resendCount;
this->currentResendCount = resendCount;
this->throttleMultiplier = ceil((throttleSensitivity / 1000.0) * this->baseResendCount);
this->throttleMultiplier = ceil((settings->packetRepeatThrottleSensitivity / 1000.0) * this->baseResendCount);
}

bool MiLightClient::available() {
Expand Down Expand Up @@ -124,18 +120,21 @@ void MiLightClient::write(uint8_t packet[]) {
}

#ifdef DEBUG_PRINTF
Serial.printf("Sending packet (%d repeats): \n", this->currentResendCount);
Serial.printf_P(PSTR("Sending packet (%d repeats): \n"), this->currentResendCount);
for (int i = 0; i < currentRemote->packetFormatter->getPacketLength(); i++) {
Serial.printf("%02X ", packet[i]);
Serial.printf_P(PSTR("%02X "), packet[i]);
}
Serial.println();
int iStart = millis();
#endif

// send the packet out (multiple times for "reliability")
for (int i = 0; i < this->currentResendCount; i++) {
currentRadio->write(packet, currentRemote->packetFormatter->getPacketLength());
}

// if we have a packetSendHandler defined (see MiLightClient::onPacketSent), call it now that
// the packet has been dispatched
if (this->packetSentHandler) {
this->packetSentHandler(packet, *currentRemote);
}
Expand All @@ -148,105 +147,168 @@ void MiLightClient::write(uint8_t packet[]) {
}

void MiLightClient::updateColorRaw(const uint8_t color) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateColorRaw: Change color to %d\n"), color);
#endif
currentRemote->packetFormatter->updateColorRaw(color);
flushPacket();
}

void MiLightClient::updateHue(const uint16_t hue) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateHue: Change hue to %d\n"), hue);
#endif
currentRemote->packetFormatter->updateHue(hue);
flushPacket();
}

void MiLightClient::updateBrightness(const uint8_t brightness) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateBrightness: Change brightness to %d\n"), brightness);
#endif
currentRemote->packetFormatter->updateBrightness(brightness);
flushPacket();
}

void MiLightClient::updateMode(uint8_t mode) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateMode: Change mode to %d\n"), mode);
#endif
currentRemote->packetFormatter->updateMode(mode);
flushPacket();
}

void MiLightClient::nextMode() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::nextMode: Switch to next mode"));
#endif
currentRemote->packetFormatter->nextMode();
flushPacket();
}

void MiLightClient::previousMode() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::previousMode: Switch to previous mode"));
#endif
currentRemote->packetFormatter->previousMode();
flushPacket();
}

void MiLightClient::modeSpeedDown() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::modeSpeedDown: Speed down\n"));
#endif
currentRemote->packetFormatter->modeSpeedDown();
flushPacket();
}
void MiLightClient::modeSpeedUp() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::modeSpeedUp: Speed up"));
#endif
currentRemote->packetFormatter->modeSpeedUp();
flushPacket();
}

void MiLightClient::updateStatus(MiLightStatus status, uint8_t groupId) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateStatus: Status %s, groupId %d\n"), status == MiLightStatus::OFF ? "OFF" : "ON", groupId);
#endif
currentRemote->packetFormatter->updateStatus(status, groupId);
flushPacket();
}

void MiLightClient::updateStatus(MiLightStatus status) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateStatus: Status %s\n"), status == MiLightStatus::OFF ? "OFF" : "ON");
#endif
currentRemote->packetFormatter->updateStatus(status);
flushPacket();
}

void MiLightClient::updateSaturation(const uint8_t value) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateSaturation: Saturation %d\n"), value);
#endif
currentRemote->packetFormatter->updateSaturation(value);
flushPacket();
}

void MiLightClient::updateColorWhite() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::updateColorWhite: Color white"));
#endif
currentRemote->packetFormatter->updateColorWhite();
flushPacket();
}

void MiLightClient::enableNightMode() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::enableNightMode: Night mode"));
#endif
currentRemote->packetFormatter->enableNightMode();
flushPacket();
}

void MiLightClient::pair() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::pair: Pair"));
#endif
currentRemote->packetFormatter->pair();
flushPacket();
}

void MiLightClient::unpair() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::unpair: Unpair"));
#endif
currentRemote->packetFormatter->unpair();
flushPacket();
}

void MiLightClient::increaseBrightness() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::increaseBrightness: Increase brightness"));
#endif
currentRemote->packetFormatter->increaseBrightness();
flushPacket();
}

void MiLightClient::decreaseBrightness() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::decreaseBrightness: Decrease brightness"));
#endif
currentRemote->packetFormatter->decreaseBrightness();
flushPacket();
}

void MiLightClient::increaseTemperature() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::increaseTemperature: Increase temperature"));
#endif
currentRemote->packetFormatter->increaseTemperature();
flushPacket();
}

void MiLightClient::decreaseTemperature() {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.println(F("MiLightClient::decreaseTemperature: Decrease temperature"));
#endif
currentRemote->packetFormatter->decreaseTemperature();
flushPacket();
}

void MiLightClient::updateTemperature(const uint8_t temperature) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::updateTemperature: Set temperature to %d\n"), temperature);
#endif
currentRemote->packetFormatter->updateTemperature(temperature);
flushPacket();
}

void MiLightClient::command(uint8_t command, uint8_t arg) {
#ifdef DEBUG_CLIENT_COMMANDS
Serial.printf_P(PSTR("MiLightClient::command: Execute command %d, argument %d\n"), command, arg);
#endif
currentRemote->packetFormatter->command(command, arg);
flushPacket();
}
Expand Down Expand Up @@ -405,10 +467,10 @@ uint8_t MiLightClient::parseStatus(const JsonObject& object) {
void MiLightClient::updateResendCount() {
unsigned long now = millis();
long millisSinceLastSend = now - lastSend;
long x = (millisSinceLastSend - throttleThreshold);
long x = (millisSinceLastSend - settings->packetRepeatThrottleThreshold);
long delta = x * throttleMultiplier;

this->currentResendCount = constrain(this->currentResendCount + delta, packetRepeatMinimum, this->baseResendCount);
this->currentResendCount = constrain(this->currentResendCount + delta, settings->packetRepeatMinimum, this->baseResendCount);
this->lastSend = now;
}

Expand All @@ -427,6 +489,9 @@ void MiLightClient::flushPacket() {
currentRemote->packetFormatter->reset();
}

/*
Register a callback for when packets are sent
*/
void MiLightClient::onPacketSent(PacketSentHandler handler) {
this->packetSentHandler = handler;
}
Expand Down