Skip to content

Commit

Permalink
Merge pull request #461 from sidoh/fix_cct_rgb_night_mode
Browse files Browse the repository at this point in the history
Fix night mode state handling for CCT and RGBW
  • Loading branch information
sidoh authored May 19, 2019
2 parents ba9aa46 + c0ded15 commit c95851d
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 17 deletions.
5 changes: 4 additions & 1 deletion lib/MiLight/CctPacketFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,10 @@ BulbId CctPacketFormatter::parsePacket(const uint8_t* packet, JsonObject result)
REMOTE_TYPE_CCT
);

if (onOffGroupId < 255) {
// Night mode
if (command & 0x10) {
result["command"] = "night_mode";
} else if (onOffGroupId < 255) {
result["state"] = cctCommandToStatus(command) == ON ? "ON" : "OFF";
} else if (command == CCT_BRIGHTNESS_DOWN) {
result["command"] = "brightness_down";
Expand Down
13 changes: 10 additions & 3 deletions lib/MiLight/RgbwPacketFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,15 @@ void RgbwPacketFormatter::updateColorWhite() {
void RgbwPacketFormatter::enableNightMode() {
uint8_t button = STATUS_COMMAND(OFF, groupId);

command(button, 0);
// Bulbs must be OFF for night mode to work in RGBW.
// Turn it off if it isn't already off.
const GroupState* state = stateStore->get(deviceId, groupId, REMOTE_TYPE_RGBW);
if (state == NULL || state->getState() == MiLightStatus::ON) {
command(button, 0);
}

// Night mode command has 0x10 bit set, but is otherwise
// a repeat of the OFF command.
command(button | 0x10, 0);
}

Expand All @@ -116,9 +124,8 @@ BulbId RgbwPacketFormatter::parsePacket(const uint8_t* packet, JsonObject result
// the last packet sent, not the current one, and that can be wrong for
// on/off commands.
bulbId.groupId = GROUP_FOR_STATUS_COMMAND(command);
} else if (command >= RGBW_ALL_MAX_LEVEL && command <= RGBW_GROUP_4_MIN_LEVEL) {
} else if (command & 0x10) {
if ((command % 2) == 0) {
result["state"] = "ON";
result["command"] = "night_mode";
} else {
result["command"] = "set_white";
Expand Down
7 changes: 6 additions & 1 deletion lib/MiLightState/GroupState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -709,10 +709,15 @@ void GroupState::patch(const GroupState& other) {
for (size_t i = 0; i < size(ALL_PHYSICAL_FIELDS); ++i) {
GroupStateField field = ALL_PHYSICAL_FIELDS[i];

// Handle night mode separately. Should always set this field.
if (field == GroupStateField::BULB_MODE && other.isNightMode()) {
setFieldValue(field, other.getFieldValue(field));
}
// Otherwise...
// Conditions:
// * Only set anything if field is set in other state
// * Do not patch anything other than STATE if bulb is off
if (other.isSetField(field) && (field == GroupStateField::STATE || isOn())) {
else if (other.isSetField(field) && (field == GroupStateField::STATE || isOn())) {
setFieldValue(field, other.getFieldValue(field));
}
}
Expand Down
1 change: 1 addition & 0 deletions test/remote/helpers/state_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module StateHelpers
ALL_REMOTE_TYPES = %w(rgb rgbw rgb_cct cct fut089 fut091)
def states_are_equal(desired_state, retrieved_state)
expect(retrieved_state).to include(*desired_state.keys)
expect(retrieved_state.select { |x| desired_state.include?(x) } ).to eq(desired_state)
Expand Down
37 changes: 25 additions & 12 deletions test/remote/spec/state_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,33 @@
end

context 'night mode command' do
it 'should affect state when bulb is off' do
state = @client.patch_state({'command' => 'night_mode'}, @id_params)

expect(state['bulb_mode']).to eq('night')
expect(state['effect']).to eq('night_mode')
StateHelpers::ALL_REMOTE_TYPES
.reject { |x| %w(rgb).include?(x) } # Night mode not supported for these types
.each do |type|
it "should affect state when bulb is OFF for #{type}" do
params = @id_params.merge(type: type)
@client.delete_state(params)
state = @client.patch_state({'command' => 'night_mode'}, params)

expect(state['bulb_mode']).to eq('night')
expect(state['effect']).to eq('night_mode')
end
end

it 'should affect state when bulb is on' do
@client.patch_state({'status' => 'ON'}, @id_params)
state = @client.patch_state({'command' => 'night_mode'}, @id_params)

expect(state['status']).to eq('ON')
expect(state['bulb_mode']).to eq('night')
expect(state['effect']).to eq('night_mode')
StateHelpers::ALL_REMOTE_TYPES
.reject { |x| %w(rgb).include?(x) } # Night mode not supported for these types
.each do |type|
it "should affect state when bulb is ON for #{type}" do
params = @id_params.merge(type: type)
@client.delete_state(params)
@client.patch_state({'status' => 'ON'}, params)
state = @client.patch_state({'command' => 'night_mode'}, params)

# RGBW bulbs have to be OFF in order for night mode to take affect
expect(state['status']).to eq('ON') if type != 'rgbw'
expect(state['bulb_mode']).to eq('night')
expect(state['effect']).to eq('night_mode')
end
end

it 'should revert to previous mode when status is toggled' do
Expand Down

0 comments on commit c95851d

Please sign in to comment.