GroupState.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. #include <GroupState.h>
  2. #include <Units.h>
  3. #include <MiLightRemoteConfig.h>
  4. #include <RGBConverter.h>
  5. const GroupId DEFAULT_GROUP_ID;
  6. const GroupState& GroupState::defaultState(MiLightRemoteType remoteType) {
  7. static GroupState instances[MiLightRemoteConfig::NUM_REMOTES];
  8. GroupState& state = instances[remoteType];
  9. switch (remoteType) {
  10. case REMOTE_TYPE_RGB:
  11. state.setBulbMode(BULB_MODE_COLOR);
  12. break;
  13. case REMOTE_TYPE_CCT:
  14. state.setBulbMode(BULB_MODE_WHITE);
  15. break;
  16. }
  17. return state;
  18. }
  19. GroupId::GroupId()
  20. : deviceId(0),
  21. groupId(0),
  22. deviceType(REMOTE_TYPE_UNKNOWN)
  23. { }
  24. GroupId::GroupId(const GroupId &other)
  25. : deviceId(other.deviceId),
  26. groupId(other.groupId),
  27. deviceType(other.deviceType)
  28. { }
  29. GroupId::GroupId(
  30. const uint16_t deviceId, const uint8_t groupId, const MiLightRemoteType deviceType
  31. )
  32. : deviceId(deviceId),
  33. groupId(groupId),
  34. deviceType(deviceType)
  35. { }
  36. void GroupId::operator=(const GroupId &other) {
  37. deviceId = other.deviceId;
  38. groupId = other.groupId;
  39. deviceType = other.deviceType;
  40. }
  41. bool GroupId::operator==(const GroupId &other) {
  42. return deviceId == other.deviceId
  43. && groupId == other.groupId
  44. && deviceType == other.deviceType;
  45. }
  46. GroupState::GroupState() {
  47. state.fields._state = 0;
  48. state.fields._brightness = 0;
  49. state.fields._brightnessColor = 0;
  50. state.fields._brightnessMode = 0;
  51. state.fields._hue = 0;
  52. state.fields._saturation = 0;
  53. state.fields._mode = 0;
  54. state.fields._bulbMode = 0;
  55. state.fields._kelvin = 0;
  56. state.fields._isSetState = 0;
  57. state.fields._isSetHue = 0;
  58. state.fields._isSetBrightness = 0;
  59. state.fields._isSetBrightnessColor = 0;
  60. state.fields._isSetBrightnessMode = 0;
  61. state.fields._isSetSaturation = 0;
  62. state.fields._isSetMode = 0;
  63. state.fields._isSetKelvin = 0;
  64. state.fields._isSetBulbMode = 0;
  65. state.fields._dirty = 1;
  66. }
  67. bool GroupState::isSetState() const { return state.fields._isSetState; }
  68. MiLightStatus GroupState::getState() const { return state.fields._state ? ON : OFF; }
  69. bool GroupState::setState(const MiLightStatus status) {
  70. if (isSetState() && getState() == status) {
  71. return false;
  72. }
  73. setDirty();
  74. state.fields._isSetState = 1;
  75. state.fields._state = status == ON ? 1 : 0;
  76. return true;
  77. }
  78. bool GroupState::isSetBrightness() const {
  79. if (! state.fields._isSetBulbMode) {
  80. return state.fields._isSetBrightness;
  81. }
  82. switch (state.fields._bulbMode) {
  83. case BULB_MODE_WHITE:
  84. return state.fields._isSetBrightness;
  85. case BULB_MODE_COLOR:
  86. return state.fields._isSetBrightnessColor;
  87. case BULB_MODE_SCENE:
  88. return state.fields._isSetBrightnessMode;
  89. }
  90. return false;
  91. }
  92. uint8_t GroupState::getBrightness() const {
  93. switch (state.fields._bulbMode) {
  94. case BULB_MODE_WHITE:
  95. return state.fields._brightness;
  96. case BULB_MODE_COLOR:
  97. return state.fields._brightnessColor;
  98. case BULB_MODE_SCENE:
  99. return state.fields._brightnessMode;
  100. }
  101. return 0;
  102. }
  103. bool GroupState::setBrightness(uint8_t brightness) {
  104. if (isSetBrightness() && getBrightness() == brightness) {
  105. return false;
  106. }
  107. setDirty();
  108. uint8_t bulbMode = state.fields._bulbMode;
  109. if (! state.fields._isSetBulbMode) {
  110. bulbMode = BULB_MODE_WHITE;
  111. }
  112. switch (bulbMode) {
  113. case BULB_MODE_WHITE:
  114. state.fields._isSetBrightness = 1;
  115. state.fields._brightness = brightness;
  116. break;
  117. case BULB_MODE_COLOR:
  118. state.fields._isSetBrightnessColor = 1;
  119. state.fields._brightnessColor = brightness;
  120. break;
  121. case BULB_MODE_SCENE:
  122. state.fields._isSetBrightnessMode = 1;
  123. state.fields._brightnessMode = brightness;
  124. default:
  125. return false;
  126. }
  127. return true;
  128. }
  129. bool GroupState::isSetHue() const { return state.fields._isSetHue; }
  130. uint16_t GroupState::getHue() const {
  131. return Units::rescale<uint16_t, uint16_t>(state.fields._hue, 360, 255);
  132. }
  133. bool GroupState::setHue(uint16_t hue) {
  134. if (isSetHue() && getHue() == hue) {
  135. return false;
  136. }
  137. setDirty();
  138. state.fields._isSetHue = 1;
  139. state.fields._hue = Units::rescale<uint16_t, uint16_t>(hue, 255, 360);
  140. return true;
  141. }
  142. bool GroupState::isSetSaturation() const { return state.fields._isSetSaturation; }
  143. uint8_t GroupState::getSaturation() const { return state.fields._saturation; }
  144. bool GroupState::setSaturation(uint8_t saturation) {
  145. if (isSetSaturation() && getSaturation() == saturation) {
  146. return false;
  147. }
  148. setDirty();
  149. state.fields._isSetSaturation = 1;
  150. state.fields._saturation = saturation;
  151. return true;
  152. }
  153. bool GroupState::isSetMode() const { return state.fields._isSetMode; }
  154. uint8_t GroupState::getMode() const { return state.fields._mode; }
  155. bool GroupState::setMode(uint8_t mode) {
  156. if (isSetMode() && getMode() == mode) {
  157. return false;
  158. }
  159. setDirty();
  160. state.fields._isSetMode = 1;
  161. state.fields._mode = mode;
  162. return true;
  163. }
  164. bool GroupState::isSetKelvin() const { return state.fields._isSetKelvin; }
  165. uint8_t GroupState::getKelvin() const { return state.fields._kelvin; }
  166. uint16_t GroupState::getMireds() const {
  167. return Units::whiteValToMireds(getKelvin(), 100);
  168. }
  169. bool GroupState::setKelvin(uint8_t kelvin) {
  170. if (isSetKelvin() && getKelvin() == kelvin) {
  171. return false;
  172. }
  173. setDirty();
  174. state.fields._isSetKelvin = 1;
  175. state.fields._kelvin = kelvin;
  176. return true;
  177. }
  178. bool GroupState::setMireds(uint16_t mireds) {
  179. return setKelvin(Units::miredsToWhiteVal(mireds, 100));
  180. }
  181. bool GroupState::isSetBulbMode() const { return state.fields._isSetBulbMode; }
  182. BulbMode GroupState::getBulbMode() const { return static_cast<BulbMode>(state.fields._bulbMode); }
  183. bool GroupState::setBulbMode(BulbMode bulbMode) {
  184. if (isSetBulbMode() && getBulbMode() == bulbMode) {
  185. return false;
  186. }
  187. setDirty();
  188. state.fields._isSetBulbMode = 1;
  189. state.fields._bulbMode = bulbMode;
  190. return true;
  191. }
  192. bool GroupState::isDirty() const { return state.fields._dirty; }
  193. inline bool GroupState::setDirty() { state.fields._dirty = 1; }
  194. bool GroupState::clearDirty() { state.fields._dirty = 0; }
  195. void GroupState::load(Stream& stream) {
  196. for (size_t i = 0; i < DATA_BYTES; i++) {
  197. stream.readBytes(reinterpret_cast<uint8_t*>(&state.data[i]), 4);
  198. }
  199. clearDirty();
  200. }
  201. void GroupState::dump(Stream& stream) const {
  202. for (size_t i = 0; i < DATA_BYTES; i++) {
  203. stream.write(reinterpret_cast<const uint8_t*>(&state.data[i]), 4);
  204. }
  205. }
  206. bool GroupState::patch(const JsonObject& state) {
  207. bool changes = false;
  208. if (state.containsKey("state")) {
  209. changes |= setState(state["state"] == "ON" ? ON : OFF);
  210. }
  211. if (state.containsKey("brightness")) {
  212. changes |= setBrightness(Units::rescale(state.get<uint8_t>("brightness"), 100, 255));
  213. }
  214. if (state.containsKey("hue")) {
  215. changes |= setHue(state["hue"]);
  216. changes |= setBulbMode(BULB_MODE_COLOR);
  217. }
  218. if (state.containsKey("saturation")) {
  219. changes |= setSaturation(state["saturation"]);
  220. }
  221. if (state.containsKey("mode")) {
  222. changes |= setMode(state["mode"]);
  223. changes |= setBulbMode(BULB_MODE_SCENE);
  224. }
  225. if (state.containsKey("color_temp")) {
  226. changes |= setMireds(state["color_temp"]);
  227. changes |= setBulbMode(BULB_MODE_WHITE);
  228. }
  229. if (state.containsKey("command")) {
  230. const String& command = state["command"];
  231. if (command == "white_mode") {
  232. changes |= setBulbMode(BULB_MODE_WHITE);
  233. } else if (command == "night_mode") {
  234. changes |= setBulbMode(BULB_MODE_NIGHT);
  235. }
  236. }
  237. return changes;
  238. }
  239. void GroupState::applyState(JsonObject& partialState) {
  240. if (isSetState()) {
  241. partialState["state"] = getState() == ON ? "ON" : "OFF";
  242. }
  243. if (isSetBrightness()) {
  244. partialState["brightness"] = Units::rescale(getBrightness(), 255, 100);
  245. }
  246. if (isSetBulbMode()) {
  247. partialState["bulb_mode"] = BULB_MODE_NAMES[getBulbMode()];
  248. if (getBulbMode() == BULB_MODE_COLOR) {
  249. if (isSetHue() && isSetSaturation()) {
  250. uint8_t rgb[3];
  251. RGBConverter converter;
  252. converter.hsvToRgb(getHue()/360.0, getSaturation()/100.0, 1, rgb);
  253. JsonObject& color = partialState.createNestedObject("color");
  254. color["r"] = rgb[0];
  255. color["g"] = rgb[1];
  256. color["b"] = rgb[2];
  257. } else if (isSetHue()) {
  258. partialState["hue"] = getHue();
  259. } else if (isSetSaturation()) {
  260. partialState["saturation"] = getSaturation();
  261. }
  262. } else if (getBulbMode() == BULB_MODE_SCENE) {
  263. if (isSetMode()) {
  264. partialState["mode"] = getMode();
  265. }
  266. } else if (getBulbMode() == BULB_MODE_WHITE) {
  267. if (isSetKelvin()) {
  268. partialState["color_temp"] = getMireds();
  269. }
  270. }
  271. }
  272. }