Bladeren bron

Merge pull request #461 from sidoh/fix_cct_rgb_night_mode

Fix night mode state handling for CCT and RGBW
Chris Mullins 6 jaren geleden
bovenliggende
commit
c95851db37

+ 4 - 1
lib/MiLight/CctPacketFormatter.cpp

@@ -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";

+ 10 - 3
lib/MiLight/RgbwPacketFormatter.cpp

@@ -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);
 }
 
@@ -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";

+ 6 - 1
lib/MiLightState/GroupState.cpp

@@ -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));
     }
   }

+ 1 - 0
test/remote/helpers/state_helpers.rb

@@ -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)

+ 25 - 12
test/remote/spec/state_spec.rb

@@ -34,20 +34,33 @@ RSpec.describe 'State' do
   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