ESP8266 Treppenlichtsteuerung mit OTA zum Firmware Upload
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.

treppe.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #include "treppe.h"
  2. // #define DEBUG_TIMING
  3. /*
  4. - dimmer_tick: increment pwm jeden tick, bis anim beendet
  5. - return: fsm_pend.anim_beendet
  6. */
  7. bool Treppe::dimmer_tick(dimmer_t *dimmer, bool dim_type) {
  8. dimmer->pwm += dimmer->delta_pwm;
  9. Serial.printf("%.0f", dimmer->pwm);
  10. if (dim_type == DIM_STUFEN) {
  11. pwmController.setChannelPWM(dimmer->stufe,
  12. static_cast<uint16_t>(dimmer->pwm));
  13. } else { // DIM_LDR
  14. pwmController.setAllChannelsPWM(static_cast<uint16_t>(dimmer->pwm));
  15. }
  16. dimmer->tick++;
  17. if (dimmer->tick < dimmer->ticks) {
  18. Serial.print("-");
  19. return false;
  20. }
  21. Serial.println("");
  22. if (dim_type == DIM_LDR) {
  23. Serial.printf("DIM_LDR: start: %d, ziel: %d\n", dimmer->start_pwm,
  24. dimmer->ziel_pwm);
  25. return true;
  26. } else // DIM_STUFEN
  27. {
  28. Serial.printf("DIM_STUFEN: stufe: %d, start: %d, ziel: %d\n",
  29. dimmer->stufe, dimmer->start_pwm, dimmer->ziel_pwm);
  30. if (fsm_outputs.laufrichtung == LR_HOCH) {
  31. if (dimmer->stufe >= stufen - 1)
  32. return true;
  33. dimmer->stufe++;
  34. } else // LR_RUNTER
  35. {
  36. if (dimmer->stufe <= 0)
  37. return true;
  38. dimmer->stufe--;
  39. }
  40. dimmer->tick = 0;
  41. dimmer->pwm = dimmer->start_pwm;
  42. }
  43. return false;
  44. }
  45. // startbedingunen für animation
  46. void Treppe::start_animation(dimmer_t *dimmer, bool dim_type, uint16_t on_pwm,
  47. uint16_t off_pwm) {
  48. fsm_pend.anim_beendet = false;
  49. if (dim_type == DIM_STUFEN) {
  50. if (fsm_outputs.laufrichtung == LR_HOCH)
  51. dimmer->stufe = 0;
  52. else
  53. dimmer->stufe = stufen - 1;
  54. dimmer->ticks = parameters.time_per_stair / INT_TIME; // [ms]
  55. } else { // DIM_LDR
  56. dimmer->ticks = parameters.time_ldr / INT_TIME; // [ms]
  57. }
  58. if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN) {
  59. dimmer->start_pwm = off_pwm;
  60. dimmer->ziel_pwm = on_pwm;
  61. dimmer->delta_pwm = (float)(on_pwm - off_pwm) / (float)dimmer->ticks;
  62. } else {
  63. dimmer->start_pwm = on_pwm;
  64. dimmer->ziel_pwm = off_pwm;
  65. dimmer->delta_pwm = (float)(off_pwm - on_pwm) / (float)dimmer->ticks;
  66. }
  67. dimmer->tick = 0;
  68. dimmer->pwm = dimmer->start_pwm;
  69. Serial.printf("stufe %d, ticks %d, delta %f, start %d, ziel %d\n",
  70. dimmer->stufe, dimmer->ticks, dimmer->delta_pwm,
  71. dimmer->start_pwm, dimmer->ziel_pwm);
  72. }
  73. void Treppe::print_state_on_change() {
  74. static FSMTreppeModelClass::ExtU_FSMTreppe_T last_in;
  75. static FSMTreppeModelClass::ExtY_FSMTreppe_T last_out;
  76. if (fsm_inputs.anim_beendet != last_in.anim_beendet ||
  77. fsm_inputs.sensor_oben != last_in.sensor_oben ||
  78. fsm_inputs.sensor_unten != last_in.sensor_unten ||
  79. fsm_inputs.ldr_schwelle != last_in.ldr_schwelle ||
  80. fsm_outputs.dimmrichtung != last_out.dimmrichtung ||
  81. fsm_outputs.laufrichtung != last_out.laufrichtung ||
  82. fsm_outputs.status != last_out.status) {
  83. last_in.anim_beendet = fsm_inputs.anim_beendet;
  84. last_in.sensor_oben = fsm_inputs.sensor_oben;
  85. last_in.sensor_unten = fsm_inputs.sensor_unten;
  86. last_in.ldr_schwelle = fsm_inputs.ldr_schwelle;
  87. last_out.dimmrichtung = fsm_outputs.dimmrichtung;
  88. last_out.laufrichtung = fsm_outputs.laufrichtung;
  89. last_out.status = fsm_outputs.status;
  90. Serial.printf("FSM IN: s_u: %d, s_o: %d, a_b: %d, l_s: %d => ",
  91. fsm_inputs.sensor_oben, fsm_inputs.sensor_unten,
  92. fsm_inputs.anim_beendet, fsm_inputs.ldr_schwelle);
  93. Serial.printf("OUT: LR: %d DR: %d ST: %d\n", fsm_outputs.laufrichtung,
  94. fsm_outputs.dimmrichtung, fsm_outputs.status);
  95. }
  96. }
  97. bool Treppe::read_sensor(int sensor) {
  98. /*
  99. reads sensors with edge detection
  100. returns true if motion was detected
  101. returns false if no motion was detected
  102. returns false if motion was detected, but state did not change back to not
  103. detected
  104. */
  105. uint8_t pegel = digitalRead(sensor);
  106. static uint8_t pegel_alt[2] = {0, 0};
  107. uint8_t index = 0;
  108. if (sensor == SENSOR_OBEN)
  109. index = 0;
  110. else
  111. index = 1;
  112. if (pegel == 1 && pegel_alt[index] == 0) {
  113. pegel_alt[index] = pegel;
  114. return true;
  115. } else {
  116. pegel_alt[index] = pegel;
  117. return false;
  118. }
  119. // return static_cast<bool>(pegel);
  120. }
  121. float Treppe::read_ldr() {
  122. /*
  123. Reads Illuminance in Lux
  124. FUTURE USE : show current Illuminance on Webserver in order to calibrate
  125. Voltage Divider 1 (R13, R14):
  126. R13 = 220k, R14 = 82k
  127. V(ADC) = V(in1) * R14/(R13+R14)
  128. -> V(in1) = V(ADC) * (R13+R14)/R14
  129. V(ADC) = analogRead(A0)/1023.00
  130. -> V(in1) = analogRead(A0)/1023.00 * (R13+R14)/R14
  131. = analogRead(A0) * (R13+R14)/(R14*1023.00)
  132. = analogRead(A0) * (220k+82k)/(82k*1023.00)
  133. = analogRead(A0) * 0.0036
  134. Voltage Divider 2 (LDR, R1 || (R13+R14))
  135. R1 = 47k, R13+R14 = 302k -> R1||(R13+R14) = 40,67k
  136. Vcc/V(in1) = R(LDR) / (R1||(R13+R14))
  137. -> R(LDR) = Vcc/V(in1) * (R1||(R13+R14))
  138. R(LDR) = 3.3V * 40.67k / V(in1)
  139. Join formulas:
  140. R(LDR) = 3.3V * 40.67k / (0.0036 * analogRead(A0))
  141. = 37280.00/analogRead(A0)
  142. ldr_ohm = R(LDR)
  143. E(LDR) = 6526.5 * R(LDR)^-2 (see Excel Regression)
  144. E(LDR) = 6526.5 / (R(LDR)^2)
  145. ldr_value = E(LDR)
  146. */
  147. float ldr_ohm = 37280.00 / analogRead(A0);
  148. float ldr_value = 6526.6 / (ldr_ohm * ldr_ohm);
  149. return ldr_value;
  150. }
  151. bool Treppe::check_ldr() {
  152. static uint8_t active = 0;
  153. #ifdef LDRDEBUG
  154. Serial.printf("R(LDR) = %f kOhm %f lux\n", ldr_value, lux);
  155. return true;
  156. #endif
  157. // follow up: averaging over many samples?
  158. float ldr = read_ldr();
  159. if (ldr < parameters.ldr_schwelle) {
  160. active = 1;
  161. }
  162. if (ldr > parameters.ldr_schwelle + LDR_HYS) {
  163. active = 0;
  164. }
  165. return active;
  166. }
  167. void Treppe::task() {
  168. #ifdef DEBUG_TIMING
  169. uint32_t m = micros();
  170. #endif
  171. // TODO wenn LDR geändert => idle_pwm_soll anpassen
  172. // fsm_pend.ldr_changed = true;
  173. fsm_inputs.ldr_schwelle = check_ldr();
  174. #ifdef DEBUG_TIMING
  175. Serial.print("1:");
  176. Serial.println(micros() - m);
  177. m = micros();
  178. #endif
  179. fsm_inputs.sensor_oben = read_sensor(SENSOR_OBEN);
  180. fsm_inputs.sensor_unten = read_sensor(SENSOR_UNTEN);
  181. fsm_inputs.anim_beendet = fsm_pend.anim_beendet;
  182. #ifdef DEBUG_TIMING
  183. Serial.print("2:");
  184. Serial.println(micros() - m);
  185. m = micros();
  186. #endif
  187. FSMTreppe_Obj.setExternalInputs(&fsm_inputs);
  188. FSMTreppe_Obj.step();
  189. fsm_outputs = FSMTreppe_Obj.getExternalOutputs();
  190. #ifdef DEBUG_TIMING
  191. Serial.print("3:");
  192. Serial.println(micros() - m);
  193. m = micros();
  194. #endif
  195. print_state_on_change();
  196. #ifdef DEBUG_TIMING
  197. Serial.print("4:");
  198. Serial.println(micros() - m);
  199. m = micros();
  200. #endif
  201. if (fsm_outputs.status == ST_AUFDIMMEN_HOCH ||
  202. fsm_outputs.status == ST_ABDIMMEN_HOCH ||
  203. fsm_outputs.status == ST_AUFDIMMEN_RUNTER ||
  204. fsm_outputs.status == ST_ABDIMMEN_RUNTER) {
  205. if (fsm_pend.anim_beendet)
  206. start_animation(&dimmer_stufen, DIM_STUFEN, parameters.active_pwm,
  207. idle_pwm_ist);
  208. else
  209. fsm_pend.anim_beendet = dimmer_tick(&dimmer_stufen, DIM_STUFEN);
  210. } else if (fsm_outputs.status == ST_AUFDIMMEN_LDR ||
  211. fsm_outputs.status == ST_ABDIMMEN_LDR) {
  212. if (fsm_pend.anim_beendet)
  213. start_animation(&dimmer_ldr, DIM_LDR, idle_pwm_ist, 0);
  214. else
  215. fsm_pend.anim_beendet = dimmer_tick(&dimmer_ldr, DIM_LDR);
  216. } else if (fsm_outputs.status == ST_RUHEZUSTAND) {
  217. if (fsm_pend.ldr_changed) {
  218. fsm_pend.ldr_changed = false;
  219. fsm_outputs.dimmrichtung = DR_AUFDIMMEN;
  220. start_animation(&dimmer_ldr, DIM_LDR, idle_pwm_soll, idle_pwm_ist);
  221. idle_pwm_ist = idle_pwm_soll;
  222. }
  223. if (!fsm_pend.anim_beendet) {
  224. fsm_pend.anim_beendet = dimmer_tick(&dimmer_ldr, DIM_LDR);
  225. }
  226. }
  227. #ifdef DEBUG_TIMING
  228. Serial.print("5:");
  229. Serial.println(micros() - m);
  230. #endif
  231. }
  232. void Treppe::setup() {
  233. pwmController.resetDevices();
  234. // Deactive PCA9685 Phase Balancer due to LED Flickering
  235. // https://github.com/NachtRaveVL/PCA9685-Arduino/issues/15
  236. // see also lib/PCA9685-Arduin/PCA9685.h:204
  237. pwmController.init(PCA9685_PhaseBalancer_None);
  238. // pwmController.init(PCA9685_PhaseBalancer_Linear);
  239. pwmController.setPWMFrequency(100);
  240. // pwmController.setAllChannelsPWM(idle_pwm);
  241. // WARNING: before getting Parameters of Flash, make sure plausible parameters
  242. // are written in flash!
  243. EEPROM.get(EEP_START_ADDR, parameters); // get Parameters of flash
  244. pinMode(13, OUTPUT);
  245. pinMode(0, OUTPUT);
  246. digitalWrite(13, HIGH);
  247. digitalWrite(0, HIGH);
  248. pinMode(A0, INPUT);
  249. pinMode(SENSOR_OBEN, INPUT);
  250. pinMode(SENSOR_UNTEN, INPUT);
  251. pinMode(OE, OUTPUT);
  252. digitalWrite(OE, 0);
  253. Serial.printf("Treppe: stufen=%d\n", stufen);
  254. }
  255. void Treppe::saveParam() {
  256. EEPROM.put(EEP_START_ADDR,
  257. parameters); // copy Parameters so "EEPROM"-section in RAM
  258. EEPROM.commit(); // write "EEPROM"-section to flash
  259. }
  260. void Treppe::set_idle_pwm_max(const uint16_t value,
  261. const vorgabe_typ_t vorgabe_typ) {
  262. if (vorgabe_typ == VORGABE_PROZENT) {
  263. parameters.idle_pwm_max = parameters.active_pwm * value / 100;
  264. } else if (vorgabe_typ == VORGABE_12BIT) {
  265. parameters.idle_pwm_max = value;
  266. }
  267. if (parameters.idle_pwm_max > parameters.active_pwm) {
  268. parameters.idle_pwm_max = parameters.active_pwm;
  269. }
  270. saveParam();
  271. Serial.printf("Treppe: parameters.idle_pwm_max=%d\n",
  272. parameters.idle_pwm_max);
  273. }
  274. void Treppe::set_active_pwm(const uint16_t value,
  275. const vorgabe_typ_t vorgabe_typ) {
  276. if (vorgabe_typ == VORGABE_PROZENT) {
  277. parameters.active_pwm = 4095 * value / 100;
  278. } else if (vorgabe_typ == VORGABE_12BIT) {
  279. parameters.active_pwm = value;
  280. }
  281. if (parameters.active_pwm > 4095) {
  282. parameters.idle_pwm_max = 4095;
  283. }
  284. saveParam();
  285. Serial.printf("Treppe: parameters.active_pwm=%d\n", parameters.active_pwm);
  286. }
  287. void Treppe::set_time_ldr(const uint16_t value) {
  288. parameters.time_ldr = value;
  289. if (parameters.time_ldr > TIME_MS_MAX)
  290. parameters.time_ldr = TIME_MS_MAX;
  291. saveParam();
  292. Serial.printf("Treppe: time_ldr=%d\n", parameters.time_ldr);
  293. }
  294. void Treppe::set_time_per_stair(const uint16_t value) {
  295. parameters.time_per_stair = value;
  296. if (parameters.time_per_stair > TIME_MS_MAX)
  297. parameters.time_per_stair = TIME_MS_MAX;
  298. saveParam();
  299. Serial.printf("Treppe: time_per_stair=%d\n", parameters.time_per_stair);
  300. }
  301. void Treppe::set_ldr_schwelle(const uint16_t value,
  302. const vorgabe_typ_t vorgabe_typ) {
  303. if (vorgabe_typ == VORGABE_PROZENT) {
  304. // ?!
  305. parameters.ldr_schwelle = 10 * value / 100;
  306. } else if (vorgabe_typ == VORGABE_12BIT) {
  307. // parameters.ldr_schwelle = value;
  308. }
  309. saveParam();
  310. Serial.printf("Treppe: ldr_schwelle=%d\n", parameters.ldr_schwelle);
  311. }