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 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #include "treppe.h"
  2. /*
  3. dimm_stufe
  4. - dimmt stufe (0 - 15, PCA9685 outputs) mit linearen ticks
  5. von idle bis active brightness
  6. - return false solange gedimmt wird
  7. - return true bei nächster stufe
  8. */
  9. bool Treppe::dimm_stufe(uint8_t stufe)
  10. {
  11. if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN)
  12. current_pwm += differenz_pwm_pro_tick;
  13. else
  14. current_pwm -= differenz_pwm_pro_tick;
  15. pwmController.setChannelPWM(stufe, static_cast<uint16_t>(current_pwm));
  16. current_tick++;
  17. if (current_tick >= ticks_pro_stufe)
  18. return false;
  19. return true;
  20. }
  21. /*
  22. animation tick
  23. - nach dem dimmen einer stufe wird die stufe weitergezählt
  24. - abbruch am ende => anim_beendet = true;
  25. */
  26. void Treppe::anim_tick()
  27. {
  28. if (!dimm_stufe(stufe))
  29. {
  30. Serial.printf("anim_tick(): stufe: %d, start: %d, ziel: %d, current %f\n",
  31. stufe, start_pwm, ziel_pwm, current_pwm);
  32. if (fsm_outputs.laufrichtung == LR_HOCH)
  33. {
  34. if (stufe >= stufen - 1)
  35. {
  36. anim_beendet = true;
  37. return;
  38. }
  39. stufe++;
  40. }
  41. else
  42. {
  43. if (stufe <= 0)
  44. {
  45. anim_beendet = true;
  46. return;
  47. }
  48. stufe--;
  49. }
  50. current_tick = 0;
  51. current_pwm = start_pwm;
  52. }
  53. }
  54. // startbedingunen für animation
  55. void Treppe::start_animation()
  56. {
  57. anim_beendet = false;
  58. if (fsm_outputs.laufrichtung == LR_HOCH)
  59. stufe = 0;
  60. else
  61. stufe = stufen - 1;
  62. if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN)
  63. {
  64. start_pwm = idle_brightness;
  65. ziel_pwm = active_brightness;
  66. }
  67. else
  68. {
  69. start_pwm = active_brightness;
  70. ziel_pwm = idle_brightness;
  71. }
  72. current_tick = 0;
  73. current_pwm = start_pwm;
  74. }
  75. void Treppe::print_state_on_change()
  76. {
  77. static FSMTreppeModelClass::ExtU_FSMTreppe_T last_in;
  78. static FSMTreppeModelClass::ExtY_FSMTreppe_T last_out;
  79. if (
  80. fsm_inputs.anim_beendet != last_in.anim_beendet ||
  81. fsm_inputs.sensor_oben != last_in.sensor_oben ||
  82. fsm_inputs.sensor_unten != last_in.sensor_unten ||
  83. fsm_outputs.dimmrichtung != last_out.dimmrichtung ||
  84. fsm_outputs.laufrichtung != last_out.laufrichtung ||
  85. fsm_outputs.status != last_out.status)
  86. {
  87. last_in.anim_beendet = fsm_inputs.anim_beendet;
  88. last_in.sensor_oben = fsm_inputs.sensor_oben;
  89. last_in.sensor_unten = fsm_inputs.sensor_unten;
  90. last_out.dimmrichtung = fsm_outputs.dimmrichtung;
  91. last_out.laufrichtung = fsm_outputs.laufrichtung;
  92. last_out.status = fsm_outputs.status;
  93. Serial.printf("FSM IN: s_u: %d, s_o: %d, beendet: %d =>",
  94. fsm_inputs.sensor_oben, fsm_inputs.sensor_unten, fsm_inputs.anim_beendet);
  95. Serial.print(" step => ");
  96. Serial.printf("OUT: LR: %d DR: %d ST: %d\n",
  97. fsm_outputs.laufrichtung, fsm_outputs.dimmrichtung, fsm_outputs.status);
  98. }
  99. }
  100. bool Treppe::read_sensor(int sensor)
  101. {
  102. /*
  103. reads sensors with edge detection
  104. returns true if motion was detected
  105. returns false if no motion was detected
  106. returns false if motion was detected, but state did not change back to not detected
  107. */
  108. uint8_t pegel = digitalRead(sensor);
  109. static uint8_t pegel_alt[2] = {0, 0};
  110. uint8_t index = 0;
  111. if (sensor == SENSOR_OBEN)
  112. index = 0;
  113. else
  114. index = 1;
  115. if (pegel == 1 && pegel_alt[index] == 0)
  116. {
  117. pegel_alt[index] = pegel;
  118. return true;
  119. }
  120. else
  121. {
  122. pegel_alt[index] = pegel;
  123. return false;
  124. }
  125. //return static_cast<bool>(pegel);
  126. }
  127. float Treppe::read_ldr(){
  128. /*
  129. Reads Illuminance in Lux
  130. FUTURE USE : show current Illuminance on Webserver in order to calibrate
  131. Voltage Divider 1 (R13, R14):
  132. R13 = 220k, R14 = 82k
  133. V(ADC) = V(in1) * R14/(R13+R14)
  134. -> V(in1) = V(ADC) * (R13+R14)/R14
  135. V(ADC) = analogRead(A0)/1023.00
  136. -> V(in1) = analogRead(A0)/1023.00 * (R13+R14)/R14
  137. = analogRead(A0) * (R13+R14)/(R14*1023.00)
  138. = analogRead(A0) * (220k+82k)/(82k*1023.00)
  139. = analogRead(A0) * 0.0036
  140. Voltage Divider 2 (LDR, R1 || (R13+R14))
  141. R1 = 47k, R13+R14 = 302k -> R1||(R13+R14) = 40,67k
  142. Vcc/V(in1) = R(LDR) / (R1||(R13+R14))
  143. -> R(LDR) = Vcc/V(in1) * (R1||(R13+R14))
  144. R(LDR) = 3.3V * 40.67k / V(in1)
  145. Join formulas:
  146. R(LDR) = 3.3V * 40.67k / (0.0036 * analogRead(A0))
  147. = 37280.00/analogRead(A0)
  148. ldr_ohm = R(LDR)
  149. E(LDR) = 79.735 * R(LDR)^-0.498 (see Excel Regression)
  150. ldr_value = E(LDR)
  151. */
  152. float ldr_ohm = 37280.00 / analogRead(A0);
  153. float ldr_value = 79.735 * pow(ldr_ohm, -0.498);
  154. return ldr_value;
  155. }
  156. bool Treppe::check_ldr()
  157. {
  158. uint8_t active = 0;
  159. #ifdef LDRDEBUG
  160. Serial.printf("R(LDR) = %f kOhm %f lux\n", ldr_value, lux);
  161. return true;
  162. #endif
  163. // follow up: averaging over many samples?
  164. if(read_ldr() < ldr_schwelle) active = 1;
  165. if(read_ldr() > ldr_schwelle + LDR_HYS) active = 0;
  166. return active;
  167. }
  168. void Treppe::task()
  169. {
  170. //Serial.printf("LDR: %f\n", ((float)analogRead(A0))/1023.*3.68);
  171. fsm_inputs.ldr_schwelle = read_ldr(); // <=== LDR implementierung !!
  172. fsm_inputs.sensor_oben = read_sensor(SENSOR_OBEN);
  173. fsm_inputs.sensor_unten = read_sensor(SENSOR_UNTEN);
  174. fsm_inputs.anim_beendet = static_cast<bool>(anim_beendet);
  175. FSMTreppe_Obj.setExternalInputs(&fsm_inputs);
  176. FSMTreppe_Obj.step();
  177. fsm_outputs = FSMTreppe_Obj.getExternalOutputs();
  178. print_state_on_change();
  179. if (fsm_outputs.status > ST_RUHEZUSTAND)
  180. {
  181. if (anim_beendet == true &&
  182. (fsm_outputs.status == ST_AUFDIMMEN_HOCH || fsm_outputs.status == ST_ABDIMMEN_HOCH ||
  183. fsm_outputs.status == ST_AUFDIMMEN_RUNTER || fsm_outputs.status == ST_ABDIMMEN_RUNTER))
  184. {
  185. start_animation();
  186. }
  187. if (!anim_beendet)
  188. anim_tick();
  189. }
  190. }
  191. void Treppe::berechne_dimmer()
  192. {
  193. ticks_pro_stufe = time_per_stair / INT_TIME; // [ms]
  194. differenz_pwm_pro_tick = (float)(active_brightness - idle_brightness) / (float)ticks_pro_stufe;
  195. }
  196. void Treppe::setup()
  197. {
  198. pwmController.resetDevices();
  199. // Deactive PCA9685 Phase Balancer due to LED Flickering
  200. // https://github.com/NachtRaveVL/PCA9685-Arduino/issues/15
  201. // see also lib/PCA9685-Arduin/PCA9685.h:204
  202. pwmController.init(PCA9685_PhaseBalancer_None);
  203. //pwmController.init(PCA9685_PhaseBalancer_Linear);
  204. pwmController.setPWMFrequency(100);
  205. pwmController.setAllChannelsPWM(idle_brightness);
  206. pinMode(A0, INPUT);
  207. pinMode(SENSOR_OBEN, INPUT);
  208. pinMode(SENSOR_UNTEN, INPUT);
  209. pinMode(OE, OUTPUT);
  210. digitalWrite(OE, 0);
  211. Serial.printf("differenz_pwm_pro_tick %f\n", differenz_pwm_pro_tick);
  212. Serial.printf("Treppe: initial parameters: stufen=%d\n", stufen);
  213. }
  214. // ###################################################################################################################
  215. // GEBUFFERT => Erst im Ruhezustand übernehmen !!!!
  216. void Treppe::set_idle_pwm(uint16_t _idle_brightness)
  217. {
  218. idle_brightness = _idle_brightness;
  219. berechne_dimmer();
  220. Serial.printf("Treppe: idle_brightness=%d\n", idle_brightness);
  221. }
  222. void Treppe::set_active_pwm(uint16_t _active_brightness)
  223. {
  224. active_brightness = _active_brightness;
  225. berechne_dimmer();
  226. Serial.printf("Treppe: active_brightness=%d\n", active_brightness);
  227. }
  228. void Treppe::set_time_per_stair(uint16_t _time_per_stair)
  229. {
  230. time_per_stair = _time_per_stair;
  231. berechne_dimmer();
  232. Serial.printf("Treppe: time_per_stair=%d\n", time_per_stair);
  233. }