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

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