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.4KB

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