S&B Volcano vaporizer remote control with Pi Pico W
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

venty.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * venty.c
  3. *
  4. * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * See <http://www.gnu.org/licenses/>.
  17. */
  18. #include "config.h"
  19. #include "log.h"
  20. #include "ble.h"
  21. #include "main.h"
  22. #include "venty.h"
  23. #define VENTY_READ_TIMEOUT_MS 500
  24. enum venty_commands {
  25. CMD_SETTINGS = 1,
  26. CMD_INTERFACE = 6,
  27. };
  28. enum venty_values {
  29. MASK_SET_TEMPERATURE = 1 << 1,
  30. MASK_SET_BOOST = 1 << 2,
  31. MASK_SET_SUPERBOOST = 1 << 3,
  32. MASK_HEATER = 1 << 5,
  33. MASK_SETTINGS = 1 << 7,
  34. };
  35. enum venty_settings {
  36. SETTING_UNIT = 1 << 0,
  37. SETTING_SETPOINT_REACHED = 1 << 1,
  38. SETTING_FACTORY_RESET = 1 << 2,
  39. SETTING_ECOMODE_CHARGE = 1 << 3,
  40. SETTING_BUTTON_CHANGED = 1 << 4,
  41. SETTING_ECOMODE_VOLTAGE = 1 << 5,
  42. SETTING_BOOST_VISUALIZATION = 1 << 6,
  43. };
  44. enum venty_interface {
  45. UI_BRIGHTNESS = 1 << 0,
  46. UI_VIBRATION = 1 << 3,
  47. };
  48. // "00000000-5354-4f52-5a26-4249434b454c"
  49. static uint8_t uuid_service[16] = {
  50. 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x4f, 0x52,
  51. 0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
  52. };
  53. // "00000001-5354-4f52-5a26-4249434b454c"
  54. static uint8_t uuid_characteristic[16] = {
  55. 0x00, 0x00, 0x00, 0x01, 0x53, 0x54, 0x4f, 0x52,
  56. 0x5a, 0x26, 0x42, 0x49, 0x43, 0x4b, 0x45, 0x4c,
  57. };
  58. static int8_t venty_cmd(uint8_t *rx, size_t rx_len,
  59. const uint8_t *tx, size_t tx_len) {
  60. int8_t r = ble_notification_enable(uuid_service, uuid_characteristic);
  61. if (r < 0) {
  62. debug("ble_notification_enable failed: %d", r);
  63. ble_notification_disable(uuid_service, uuid_characteristic);
  64. return r;
  65. }
  66. r = ble_write(uuid_service, uuid_characteristic,
  67. tx, tx_len);
  68. if (r < 0) {
  69. debug("ble_write failed: %d", r);
  70. ble_notification_disable(uuid_service, uuid_characteristic);
  71. return r;
  72. }
  73. uint32_t start_time = to_ms_since_boot(get_absolute_time());
  74. while (!ble_notification_ready()) {
  75. sleep_ms(1);
  76. main_loop_hw();
  77. uint32_t now = to_ms_since_boot(get_absolute_time());
  78. if ((now - start_time) >= VENTY_READ_TIMEOUT_MS) {
  79. debug("timeout waiting for notification");
  80. ble_notification_disable(uuid_service, uuid_characteristic);
  81. return -1;
  82. }
  83. }
  84. uint8_t uuid[16] = {0};
  85. uint16_t len = ble_notification_get(rx, rx_len, uuid);
  86. if (memcmp(uuid, uuid_characteristic, 16) != 0) {
  87. debug("got notification for unexpected uuid");
  88. len = 0;
  89. }
  90. ble_notification_disable(uuid_service, uuid_characteristic);
  91. return (len <= 0) ? -1 : 0;
  92. }
  93. int16_t venty_get_target_temp(void) {
  94. uint8_t cmd[20] = {0};
  95. uint8_t buff[20] = {0};
  96. cmd[0] = CMD_SETTINGS;
  97. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  98. if (r < 0) {
  99. return r;
  100. }
  101. int16_t *val = (int16_t *)(buff + 4);
  102. return *val;
  103. }
  104. int8_t venty_set_target_temp(uint16_t value) {
  105. uint8_t cmd[20] = {0};
  106. uint8_t buff[20] = {0};
  107. cmd[0] = CMD_SETTINGS;
  108. cmd[1] = MASK_SET_TEMPERATURE;
  109. uint16_t *val = (uint16_t *)(cmd + 4);
  110. *val = value;
  111. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  112. return r;
  113. }
  114. int8_t venty_get_heater_state(void) {
  115. uint8_t cmd[20] = {0};
  116. uint8_t buff[20] = {0};
  117. cmd[0] = CMD_SETTINGS;
  118. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  119. if (r < 0) {
  120. return r;
  121. }
  122. int8_t *val = (int8_t *)(buff + 11);
  123. return *val;
  124. }
  125. int8_t venty_set_heater_state(bool value) {
  126. uint8_t cmd[20] = {0};
  127. uint8_t buff[20] = {0};
  128. cmd[0] = CMD_SETTINGS;
  129. cmd[1] = MASK_HEATER;
  130. cmd[11] = value ? 1 : 0;
  131. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  132. return r;
  133. }
  134. int8_t venty_get_battery_state(void) {
  135. uint8_t cmd[20] = {0};
  136. uint8_t buff[20] = {0};
  137. cmd[0] = CMD_SETTINGS;
  138. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  139. if (r < 0) {
  140. return r;
  141. }
  142. int8_t *val = (int8_t *)(buff + 8);
  143. return *val;
  144. }
  145. int8_t venty_get_eco_current(void) {
  146. uint8_t cmd[20] = {0};
  147. uint8_t buff[20] = {0};
  148. cmd[0] = CMD_SETTINGS;
  149. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  150. if (r < 0) {
  151. return r;
  152. }
  153. int8_t *val = (int8_t *)(buff + 14);
  154. return (*val & SETTING_ECOMODE_CHARGE) ? 1 : 0;
  155. }
  156. int8_t venty_get_eco_voltage(void) {
  157. uint8_t cmd[20] = {0};
  158. uint8_t buff[20] = {0};
  159. cmd[0] = CMD_SETTINGS;
  160. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  161. if (r < 0) {
  162. return r;
  163. }
  164. int8_t *val = (int8_t *)(buff + 14);
  165. return (*val & SETTING_ECOMODE_VOLTAGE) ? 1 : 0;
  166. }
  167. int8_t venty_set_eco_current(bool value) {
  168. uint8_t cmd[20] = {0};
  169. uint8_t buff[20] = {0};
  170. cmd[0] = CMD_SETTINGS;
  171. cmd[1] = MASK_SETTINGS;
  172. cmd[14] = value ? SETTING_ECOMODE_CHARGE : 0;
  173. cmd[15] = SETTING_ECOMODE_CHARGE;
  174. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  175. return r;
  176. }
  177. int8_t venty_set_eco_voltage(bool value) {
  178. uint8_t cmd[20] = {0};
  179. uint8_t buff[20] = {0};
  180. cmd[0] = CMD_SETTINGS;
  181. cmd[1] = MASK_SETTINGS;
  182. cmd[14] = value ? SETTING_ECOMODE_VOLTAGE : 0;
  183. cmd[15] = SETTING_ECOMODE_VOLTAGE;
  184. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  185. return r;
  186. }
  187. int8_t venty_get_vibration(void) {
  188. uint8_t cmd[6] = {0};
  189. uint8_t buff[6] = {0};
  190. cmd[0] = CMD_INTERFACE;
  191. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  192. if (r < 0) {
  193. return r;
  194. }
  195. int8_t *val = (int8_t *)(buff + 5);
  196. return *val;
  197. }
  198. int8_t venty_get_brightness(void) {
  199. uint8_t cmd[6] = {0};
  200. uint8_t buff[6] = {0};
  201. cmd[0] = CMD_INTERFACE;
  202. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  203. if (r < 0) {
  204. return r;
  205. }
  206. int8_t *val = (int8_t *)(buff + 2);
  207. return *val;
  208. }
  209. int8_t venty_set_vibration(bool value) {
  210. uint8_t cmd[6] = {0};
  211. uint8_t buff[6] = {0};
  212. cmd[0] = CMD_INTERFACE;
  213. cmd[1] = UI_VIBRATION;
  214. cmd[5] = value ? 1 : 0;
  215. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  216. return r;
  217. }
  218. int8_t venty_set_brightness(uint8_t value) {
  219. uint8_t cmd[6] = {0};
  220. uint8_t buff[6] = {0};
  221. cmd[0] = CMD_INTERFACE;
  222. cmd[1] = UI_BRIGHTNESS;
  223. cmd[2] = MIN(MAX(value, 1), 9);
  224. int8_t r = venty_cmd(buff, sizeof(buff), cmd, sizeof(cmd));
  225. return r;
  226. }