uint8_t get_heiz_details(uint8_t heiz_id, uint8_t *mode, uint8_t *rate, int16_t *Tsoll, uint16_t *dauer, uint16_t *Tist) { canix_frame message; heiz_details_heiz_id = heiz_id; heiz_details_Tsoll = 0; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_HEIZUNG_DETAILS_REQUEST; message.data[2] = heiz_id; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); heiz_details_expected = 1; // Bit 0 = HCAN_HES_HEIZUNG_DETAILS_REQUEST // Auf die Anwort warten canix_sleep_100th(5); // ... und noch nach T(ist) fragen... message.data[1] = HCAN_HES_HEIZUNG_TIST_REQUEST; message.data[2] = heiz_id; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); heiz_details_expected = 2; // Bit 1 = HCAN_HES_HEIZUNG_TIST_REQUEST // Auf die Anwort warten canix_sleep_100th(5); if (heiz_details_expected == 0) { // aha, es ist eine Antwort eingetroffen... *mode = heiz_details_mode; *rate = heiz_details_rate; *Tsoll = heiz_details_Tsoll; *Tist = heiz_details_Tist; *dauer = heiz_details_dauer; heiz_details_heiz_id = 0; return 0; } // Timeout... keine Antwort erhalten :-( return 1; }
void powerport_page_print_page(eds_powerport_page_block_t *p) { char s[40]; canix_frame message; // LCD Bildschirm loeschen lcd_clrscr(); // 1. Zeile snprintf_P(s,sizeof(s), PSTR("%s"), p->line0); lcd_gotoxy(0,0); lcd_puts(s); snprintf_P(s,sizeof(s), PSTR("%s"), p->line1); lcd_gotoxy(0,1); lcd_puts(s); // In powerport_page_state wird spaeter der State gespeichert; sollte // keine Meldung eintreffen, so nuetzt es nichts, wenn der User OK // drueckt - man weiss ja den State nicht und kann ihn nicht aendern! // Das erkennt man am Wert -1 powerport_page_state = -1; powerport_page_timer = -1; // nun den Status des Powerports erfragen und (asynchron) // in powerport_page_can_callback weitermachen message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_POWER_GROUP_STATE_QUERY; message.data[2] = p->gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); canix_sleep_100th(1); message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_POWER_GROUP_TIMER_QUERY; message.data[2] = p->gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
void rolladen_page_handle_key_down_event(eds_rolladen_page_block_t *p, uint8_t key) { if (key == KEY_OK) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[2] = p->gruppe; message.data[3] = p->pos; message.size = 4; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); lcdctrl_blink(); return; } if (key == KEY_ESC) { goto_page_up(); return; } if (key == KEY_UP) goto_prev_page(); if (key == KEY_DOWN) goto_next_page(); }
static inline void sendMessage(device_data_schalter *p, uint8_t active) { canix_frame message; if(active) p->lastEdge = RISING; else p->lastEdge = FALLING; if(p->config.feature & (1<<FEATURE_SCHALTER_INVERTIEREN)) active = !active; // invertieren message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; if(active) { if(p->config.feature & (1<<FEATURE_SCHALTER_MUTE)) message.data[1] = HCAN_HES_MUTE_ON; else message.data[1] = HCAN_HES_SCHALTER_ON; } else { if(p->config.feature & (1<<FEATURE_SCHALTER_MUTE)) message.data[1] = HCAN_HES_MUTE_OFF; else message.data[1] = HCAN_HES_SCHALTER_OFF; } message.data[2] = p->config.gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
uint8_t get_weck_details(uint8_t weck_id, uint16_t *dauer) { canix_frame message; weck_details_weck_id = weck_id; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_WECKER_DETAILS_REQUEST; message.data[2] = weck_id; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); weck_details_expected = 1; // Bit 0 = HCAN_HES_WECKER_DETAILS_REQUEST // Auf die Anwort warten canix_sleep_100th(5); if (weck_details_expected == 0) { // aha, es ist eine Antwort eingetroffen... (und zwar HCAN_HES_WECKER_DETAILS) *dauer = weck_details_dauer; weck_details_weck_id = 0; return 0; } // Timeout... keine Antwort erhalten :-( return 1; }
void set_weck_edited_details(eds_weck_page_block_t *p) { canix_frame message; // 1. herausfinden, welcher Parameter geaendert wurde message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_WECKER_SET; message.data[2] = p->weck_id; //=Powerport-Gruppe message.data[3] = POWERPORT_FEATURE_WECK_VERZOEGERT_EIN; //Vorbelegung if ( p->feature & (1<<POWERPORT_FEATURE_WECK_VERZOEGERT_EIN) ) { message.data[3] = POWERPORT_FEATURE_WECK_VERZOEGERT_EIN; } else if ( p->feature & (1<<POWERPORT_FEATURE_WECK_AUTO_AUS) ) { message.data[3] = POWERPORT_FEATURE_WECK_AUTO_AUS; } message.data[4] = weck_details_dauer_edit >> 8; //Dauer bis Wecker einschaltet message.data[5] = weck_details_dauer_edit; //LSB message.size = 6; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
inline void rolladenSchlitzpos_timer_handler(device_data_rolladenSchlitzpos *p, uint8_t zyklus) { if (zyklus != 10) return; // 10tel-Sekunden-Zyklus verwendet canix_frame message; if(p->rolladenSchlitzJob < SCHLITZ_JOB_ABGEMELDET) //ist der Job angemeldet { p->rolladenSchlitzJob--; //es sind wieder 100 ms vergangen //canix_syslog_P(SYSLOG_PRIO_DEBUG, PSTR("p->rolladenSchlitzJob=%d"), p->rolladenSchlitzJob); if(p->rolladenSchlitzJob == 0) { p->rolladenSchlitzJob = SCHLITZ_JOB_ABGEMELDET; /* Warte zwei Sekunden. Falls das Fenster wieder geoeffnet wird, * wird der rolladenSchlitzJob wieder abgemeldet, * die HCAN_HES_REEDKONTAKT_STATE_QUERY nicht gesendet * und somit der Rollladen nicht geschlossen. * ...und dann in HCAN_HES_REEDKONTAKT_STATE_REPLAY die Abfrage, * ob der Reedkontakt immer noch zu ist: */ message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_REQUEST; message.data[2] = p->config.rolladen; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); //rolladenIstposition-Abfrage //und Reedkontakt(e) abfragen: message.data[1] = HCAN_HES_REEDKONTAKT_STATE_QUERY; message.data[2] = p->config.reed0; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); if(p->config.reed1 != 255) //zweiter Reedkontakt vorhanden? { message.data[2] = p->config.reed1; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); } } } }
void taster_page_handle_key_down_event(eds_taster_page_block_t *p, uint8_t key) { if (key == KEY_OK) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_TASTER_DOWN; message.data[2] = p->gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); canix_sleep_100th(1); message.data[1] = HCAN_HES_TASTER_UP; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); lcdctrl_blink(); return; } if (key == KEY_ESC) { goto_page_up(); return; } if (key == KEY_UP) goto_prev_page(); if (key == KEY_DOWN) goto_next_page(); }
static inline void sendMessage(device_data_zentralheizungspumpe *p, uint8_t zustandToSend) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = zustandToSend; // Zentralheizungspumpe schalten message.data[2] = p->config.gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
void send_rolladen_position_set(device_data_rolladenSchlitzpos *p, uint8_t soll_position) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[2] = p->config.rolladen; message.data[3] = soll_position; //gewuenschte Rollladenposition: z.B. Pos: 0=zu, SCHLITZ_POS message.size = 4; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); }
/** Der poti_timer_handler liest den ADC-Wert des * konfigurierten Potis und sendet diesen auf den CAN-Bus. */ inline void poti_timer_handler(device_data_poti *p, uint8_t zyklus) { if (zyklus != 10) return; // 10tel-Sekunden-Zyklus verwendet int16_t currentADCvalue; setADMUX(p->config.port); currentADCvalue = getADCvalue(); if (p->potiTelegramCountdown) { /* Abfrage, ob sich der ADC-Wert signifikant aenderte, * gegenueber dem Wert im letzten Potitelegramm (Filterung): */ if ( ( currentADCvalue > (p->lastPotiValue + POTI_VALUE_TOLERANCE) ) || ( currentADCvalue < (p->lastPotiValue - POTI_VALUE_TOLERANCE) ) ) { //sign. Potiwertaenderung gegenueber dem currentADCvalue p->potiTelegramCountdown--; } else { //Potiwert wieder der gleiche Wert (oder zumindest in etwa) p->potiTelegramCountdown = POTI_TELEGRAM_COUNTDOWN_INIT; } } else //p->potiTelegramCountdown == 0 { //Das Potitelegramm senden: p->lastPotiValue = currentADCvalue; //Angleich p->potiTelegramCountdown = POTI_TELEGRAM_COUNTDOWN_INIT; //sende das Potitelegramm: canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_POTI_POS_CHANGED; message.data[2] = p->config.gruppe; message.data[3] = (uint8_t)((currentADCvalue & 0xFF00) >> 8); //high value message.data[4] = (uint8_t)currentADCvalue; //low value message.size = 5; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); } }
static void rolladen_send_changed_info(device_data_rolladen *p, uint8_t pos) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_CHANGED_INFO; message.data[2] = p->config.taster; message.data[3] = pos; // aktuelle Position in % message.data[4] = 0; // Quelle des cmd: nicht verwendet message.data[5] = 0; // Quelle des cmd: nicht verwendet message.size = 6; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
/** * Fragt alle konfigurierten Reedkontakte nach ihrem Status und sammelt * die Ergebnisse in fenster_monitor_reed_state; liefert die Anzahl der * offenen Reedkontakte zurueck */ uint8_t fenster_monitor_collect_reed_states(eds_fenster_monitor_page_block_t *p) { uint8_t i,n_reed_open; uint8_t *reeds = (uint8_t *)(&p->reed0); // Ergebnis-Array initialisieren: for (i = 0; i < 24; i++) fenster_monitor_reed_state[i] = 255; // ueber alle Reedkontakte iterieren: for (i = 0; i < 24; i++) { if (reeds[i] != 255) // ist es ein konfigurierter Reedkontakt? { // Nach Kontakt-Status fragen; die Ergebnisse kommen asynchron // ueber den CAN Handler rein canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_REEDKONTAKT_STATE_QUERY; message.data[2] = reeds[i]; // die Reedkontakt-Gruppen-ID message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); canix_sleep_100th(10); // 100msec Pause } wdt_reset(); } // Reedkontakte zaehlen: n_reed_open = 0; for (i = 0; i < 24; i++) { if ((fenster_monitor_reed_state[i]) && (fenster_monitor_reed_state[i] != 255)) n_reed_open++; } return n_reed_open; }
/** * Fragt alle konfigurierten Reedkontakte nach ihrem Status und sammelt * die Ergebnisse in monitor_reedkontakt_state */ static void init_monitor_reedkontakt_request_states(void) { eds_block_p it = eds_find_next_block((eds_block_p)0, EDS_userpanel_reedkontakte_BLOCK_ID); if (!it) { load_error_page(ERROR_CONF_REEDKONTAKTE_MISSING); reedkontakt_configured = 0; return; } userpanel_reedkontakte_t c; eeprom_read_block(&c, (it+2), sizeof(c)); uint8_t i; // Ergebnis-Array initialisieren: for (i = 0; i < 24; i++) monitor_reedkontakt_state[i] = 255; // ueber alle Reedkontakte iterieren: for (i = 0; i < 24; i++) { if (c.reed[i] != 255) // ist es ein konfigurierter Reedkontakt? { // Nach Kontakt-Status fragen; die Ergebnisse kommen asynchron // ueber den CAN Handler rein canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_REEDKONTAKT_STATE_QUERY; message.data[2] = c.reed[i]; // die Reedkontakt-Gruppen-ID message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); canix_sleep_100th(10); // 100msec Pause } wdt_reset(); } }
static inline void sendMessage(device_data_powerportAutomat *p, uint8_t active) { canix_frame message; // Helligkeitssensor: if( p->automatikEin // Automatikbetrieb && (HCAN_HES_POWER_GROUP_ON == active) // HCAN_HES_POWER_GROUP_OFF soll immer moeglich sein && (p->brightness != 65535) // Helligkeitssensor verwenden? && (p->brightness > p->config.helligkeitsschwelle) ) // zu hell? { return; // zu hell -> kein HCAN_HES_POWER_GROUP_ON senden } message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = active; // HCAN_HES_POWER_GROUP_ON oder HCAN_HES_POWER_GROUP_OFF message.data[2] = p->config.powerport_gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
/** Der helligkeitssensor_timer_handler wird alle 1 s aufgerufen: Er liest den ADC-Wert des * konfigurierten helligkeitssensors und sendet diesen auf den CAN-Bus. */ inline void helligkeitssensor_timer_handler(device_data_helligkeitssensor *p, uint8_t zyklus) { if (zyklus != 1) return; // 1s-Zyklus verwendet uint16_t currentADCaverage; if (p->secsUntilNextSend) { p->secsUntilNextSend--; // nur die letzten n Werte vorm Senden sind wichtig: if(p->secsUntilNextSend <= SIZE_OF_AVG) { setADMUX(p->config.port); addToFloatAvg(&(p->filterBrightness), getADCvalue_inverted()); } } else { currentADCaverage = getOutputValue(&(p->filterBrightness)); // sende das Helligkeitssensortelegramm: canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_HELLIGKEITS_INFO; //z.B. fuer rolladenAutomat-Device message.data[2] = p->config.gruppe; message.data[3] = (uint8_t)((currentADCaverage & 0xFF00) >> 8); //high value message.data[4] = (uint8_t)currentADCaverage; //low value message.size = 5; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); p->secsUntilNextSend = (uint16_t) 60 * p->config.sendCycleMins; } }
/** * Sendet Updates an alle Action-Gruppen */ void inform_action_groups(const device_data_lichtzone *p) { canix_frame answer; uint8_t *action_group; uint8_t i; action_group = (uint8_t *)&(p->config.action_gruppe0); for (i = 0; i < 2; i++) { if (action_group[i] != 255) { answer.src = canix_selfaddr(); answer.dst = HCAN_MULTICAST_CONTROL; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_HES; answer.data[1] = p->state != 0 ? HCAN_HES_POWER_GROUP_ON : HCAN_HES_POWER_GROUP_OFF; answer.data[2] = action_group[i]; answer.size = 3; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); } } }
inline void taster_timer_handler(device_data_taster *p, uint8_t zyklus) { if (zyklus != 100) return; // 100tel-Sekunden-Zyklus verwendet canix_frame message; uint8_t time; // Wenn Taste gedrueckt ist, dann ist der Pin 0, ansonsten 1 uint8_t status = ! tasterport_read(p->config.port); // Message schon mal vorbereiten: message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; // message.data[1] wird unten ausgefuellt message.data[2] = p->config.gruppe; // message.data[3] wird unten ausgefuellt message.size = 4; if (status) // gedrueckt { // Entprellschutz: if (p->pressed < 255) p->pressed++; } else { // Wenn Schalter-Down schon gesendet wurde, // dann ein Schalter-Up Event senden: if (p->pressed > 3) { // ...und kein Flankenbetrieb konfiguriert ist: if (p->config.feature & ((1<<FEATURE_TASTER_ROLLADEN_ZU) | (1<<FEATURE_TASTER_ROLLADEN_AUF)) ) { message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[3] = 222; // "Taster up" im Rolladen 2-Taster-Betrieb canix_frame_send_with_prio(&message, HCAN_PRIO_HI); } else if ( !(p->config.feature & ((1<<FEATURE_TASTER_POWERPORT_AN) | (1<<FEATURE_TASTER_POWERPORT_AUS) )) ) { message.data[1] = HCAN_HES_TASTER_UP; message.data[3] = p->config.port; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); } } p->pressed = 0; // Taste wurde losgelassen, also Zaehler zuruecksetzen } if (p->config.feature & (1<<FEATURE_TASTER_ENTPRELL_1S)) time = 100; else time = 3; if (p->pressed == time) // mind. 30msec gedrueckt { if (p->config.feature & (1<<FEATURE_TASTER_ROLLADEN_ZU)) { message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[3] = 200; // gewuenschte Rollladenposition: Pos=200=0%=zu } else if (p->config.feature & (1<<FEATURE_TASTER_ROLLADEN_AUF)) { message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[3] = 201; // gewuenschte Rollladenposition: Pos=201=100%=auf } else if (p->config.feature & (1<<FEATURE_TASTER_POWERPORT_AN)) { message.data[1] = HCAN_HES_POWER_GROUP_ON; message.size = 3; } else if (p->config.feature & (1<<FEATURE_TASTER_POWERPORT_AUS)) { message.data[1] = HCAN_HES_POWER_GROUP_OFF; message.size = 3; } else // kein z.B. Rollladentaster im 2-Tasterbetrieb { message.data[1] = HCAN_HES_TASTER_DOWN; message.data[3] = p->config.port; } canix_frame_send_with_prio(&message, HCAN_PRIO_HI); } }
void canix_frame_send(const canix_frame *frame) { canix_frame_send_with_prio(frame, HCAN_PRIO_LOW); }
void powerport_page_handle_key_down_event(eds_powerport_page_block_t *p, uint8_t key) { if (key == KEY_OK) { if ((powerport_page_state == 1) && (powerport_page_timer > 0)) { // Powerport ist eingeschaltet und der Timer laeuft; in diesem // Fall schaltet die OK Taste den Timer aus, laesst aber den // Powerport an // canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_POWER_GROUP_SET_TIMER; message.data[2] = p->gruppe; message.data[3] = 0; message.data[4] = 0; message.size = 5; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); lcdctrl_blink(); canix_sleep_100th(5); powerport_page_print_page(p); return; } // Wenn der Powerport ein oder aus ist: if (powerport_page_state != -1) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = powerport_page_state ? HCAN_HES_POWER_GROUP_OFF : HCAN_HES_POWER_GROUP_ON; message.data[2] = p->gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); lcdctrl_blink(); canix_sleep_100th(5); powerport_page_print_page(p); return; } } if (key == KEY_ESC) { goto_page_up(); return; } if (key == KEY_UP) goto_prev_page(); if (key == KEY_DOWN) goto_next_page(); }
/** multitaster_timer_handler sendet eine Taster UP-/DOWN-Nachricht * auf den CAN-Bus. Der multitaster_timer_handler wird alle 10msec aufgerufen. */ void multitaster_timer_handler(device_data_multitaster *p) { canix_frame message; uint8_t time; // Wenn Taste gedrueckt ist, dann ist der Pin 0, ansonsten 1 uint8_t status = ! tasterport_read(p->config.taster_port); // Message schon mal vorbereiten: message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; // message.data[1] wird unten ausgefuellt message.data[2] = getGroup(p); // message.data[3] wird unten ausgefuellt message.size = 4; if (status) // gedrueckt { // Entprellschutz: if (p->pressed < 255) p->pressed++; } else { // Wenn Schalter-Down schon gesendet wurde, // dann ein Schalter-Up Event senden: if (p->pressed > 3) { //...und kein Rollladentaster im 2-Tasterbetrieb konfiguriert ist: if ( !(p->config.feature & ((1<<FEATURE_MULTITASTER_ROLLADEN_ZU) | (1<<FEATURE_MULTITASTER_ROLLADEN_AUF))) ) { message.data[1] = HCAN_HES_TASTER_UP; message.data[3] = p->config.taster_port; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); } } // Taste wurde losgelassen, also Zaehler zuruecksetzen p->pressed = 0; } if (p->config.feature & (1<<FEATURE_MULTITASTER_ENTPRELL_1S)) time = 100; else time = 3; if (p->pressed == time) // mind. 30msec gedrueckt { if (p->config.feature & (1<<FEATURE_MULTITASTER_ROLLADEN_ZU)) { message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[3] = 200; //gewuenschte Rollladenposition: Pos=200=0%=zu } else if (p->config.feature & (1<<FEATURE_MULTITASTER_ROLLADEN_AUF)) { message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[3] = 201; //gewuenschte Rollladenposition: Pos=201=100%=auf } else //kein Rollladentaster im 2-Tasterbetrieb { message.data[1] = HCAN_HES_TASTER_DOWN; message.data[3] = p->config.taster_port; } canix_frame_send_with_prio(&message, HCAN_PRIO_HI); } }
/** * this timer handler is called every second */ void heizung_timer_handler(device_data_heizung *p) { if (p->ventilpflege_counter > 0) p->ventilpflege_counter--; // Ventilpflege aktivieren, falls der richtige Zeitpunkt dazu ist: heizung_check_ventilpflege(p); if (p->received_interval_counter != 0xff) p->received_interval_counter++; heizung_handle_pwm(p); if (p->duration_counter > 0) { p->duration_counter -= 1; if (p->duration_counter == 0) { // Zeit ist abgelaufen; nun wieder auf Automatik-Modus // stellen: // p->mode = HEIZUNG_MODE_AUTOMATIK; } } if (p->reed_heiz_stop_counter > 0) { p->reed_heiz_stop_counter -= 1; if (p->reed_heiz_stop_counter == 0) { canix_syslog_P(SYSLOG_PRIO_DEBUG, PSTR("heiz-stop ende (heizung %d)"), p->config.id); } } /* * Schaltet die HK-Ventile aus, wenn ein Heizstop vorliegt. Dies passiert * in regelmaessigen Abstaenden, da eventuell aufgrund der Heizsteuerlogik * die PWM nicht regelmaessig upgedatet wird und so das HK-Ventil nicht auf * den Reedkontakt reagiert. */ heizung_update_heizstop(p); if (p->timer_counter++ >= 5) { p->timer_counter = 0; switch (p->mode) { case HEIZUNG_MODE_OFF : { if (p->ventilpflege_counter) { // Sonderfall: Ventilpflege ist aktiv; dazu // Ventil einschalten, sonst aber nichts // unternehmen: p->manual_rate = 0; // Ventil einschalten: heizung_set_pwm(p,100); darlingtonoutput_setpin(p->config.port, 1); canix_syslog_P(SYSLOG_PRIO_DEBUG, PSTR("ventilpflege: 1")); } else { // das ist Normalfall: keine Ventilpflege aktiv. p->manual_rate = 0; heizung_set_pwm(p,0); // Ventil ausschalten, falls es an ist: if (darlingtonoutput_getpin(p->config.port)) darlingtonoutput_setpin(p->config.port, 0); } return; } case HEIZUNG_MODE_MANUAL : { heizung_set_pwm(p, p->manual_rate); } break; case HEIZUNG_MODE_AUTOMATIK : { // Wenn ein gueltiger Messwert vorliegt // (d.h. wenn innerhalb eines definierten Zeitraumes // ein Sensor-Messwert eingetroffen ist: if (p->received_interval_counter < 255) { int8_t index; index = heizung_get_matching_zeitzone_index(p); if (index != -1) { // we got an zeitzone which matches solltemp_line_t *solltemp_line = (solltemp_line_t*) &(p->config.zeitzone0_id); heizung_set_pwm_by_temp(p, solltemp_line[index].temp, p->measure_value); } else { // keine passende Zeitzone gefunden heizung_set_pwm(p,0); } } else { canix_syslog_P(SYSLOG_PRIO_ERROR, PSTR("keine Sensor-Messwerte vorhanden!")); } } break; case HEIZUNG_MODE_THERMOSTAT : { // Wenn ein gueltiger Messwert vorliegt // (d.h. wenn innerhalb eines definierten Zeitraumes // ein Sensor-Messwert eingetroffen ist: if (p->received_interval_counter < 255) { heizung_set_pwm_by_temp(p, p->thermostat_temp, p->measure_value); } else { canix_syslog_P(SYSLOG_PRIO_ERROR, PSTR("keine Sensor-Messwerte vorhanden!")); } } break; } } // Waermebedarfsmeldung versenden: if (p->waermebedarf_counter-- == 0) { canix_frame message; // Waermebedarfsmeldungen alle 60 Sekunden p->waermebedarf_counter = 60; // den aktuellen Ventilstand / Heizrate ermitteln: uint8_t rate = heizung_get_pwm(p); // Feature-Bit testen, und ggfls Waermebedarf verdoppeln: if (p->config.feature & (1<<HEIZUNG_FEATURE_DOPPEL_WAERMEBEDARF)) rate = rate << 1; // Der Waermebedarf ist proportional zur Ventilstellung, d.h. // der Bedarf ist hoch, wenn das Ventil voll offen ist, und ist // nicht vorhanden, wenn das Ventil zu ist. message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_HEIZUNG_WAERMEBEDARF_INFO; message.data[2] = p->config.id; message.data[3] = rate; message.size = 4; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); } }
void rolladen_can_callback(device_data_rolladen *p, const canix_frame *frame) { canix_frame answer; answer.src = canix_selfaddr(); answer.dst = frame->src; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_HES; switch (frame->data[1]) { case HCAN_HES_ROLLADEN_POSITION_SET: if (is_group_in_rolladen(p, frame->data[2])) { switch (frame->data[3]) { case 200: // Taster-Down im 2-Taster-Betrieb: ZU = 0 % if (p->mute || p->blockingTimer) return; // Befehl abblocken if (p->power || p->soll_power) rolladen_cmd_stop (p); // anhalten, falls der Rolladen faehrt else if (set_soll_laufzeit(p, ROLLADEN_DIR_AB)) { // noch nicht in soll-Position: p->long_pressed_counter = 10; // 1 s rolladen_cmd_drive (p); } break; case 201: // Taster-Down im 2-Taster-Betrieb: AUF = 100 % if (p->mute || p->blockingTimer) return; // Befehl abblocken if (p->power || p->soll_power) rolladen_cmd_stop (p); // anhalten, falls der Rolladen faehrt else if (set_soll_laufzeit(p, ROLLADEN_DIR_AUF)) // noch nicht in soll-Position? { // noch nicht in soll-Position: p->long_pressed_counter = 10; // 1 s rolladen_cmd_drive (p); } break; case 202: // HALT ueber Web-Interface p->long_pressed_counter = -1; // abmelden (2-Taster-Betrieb) rolladen_cmd_stop (p); break; case 222: // Taster-Up im 2-Taster-Betrieb p->long_pressed_counter = -1; // abmelden break; default: // frame->data[3] = Positionsvorgabe in % if (p->mute || p->blockingTimer) return; // Befehl abblocken p->soll_laufzeit = (int32_t)p->config.laufzeit * frame->data[3] / 100; canix_syslog_P(SYSLOG_PRIO_DEBUG, PSTR("s %d"), p->soll_laufzeit); if (p->soll_laufzeit < 0) p->soll_laufzeit = 0; if (p->soll_laufzeit > p->config.laufzeit) p->soll_laufzeit = p->config.laufzeit; if (p->power || p->soll_power || p->soll_laufzeit == p->laufzeit) { p->soll_laufzeit = -1; return; // ignorieren, falls der Rolladen faehrt oder die Soll-Pos. schon hat } p->kalibrieren = 0; // nicht kalibrieren if (p->soll_laufzeit < p->laufzeit) p->soll_dir = ROLLADEN_DIR_AB; else p->soll_dir = ROLLADEN_DIR_AUF; rolladen_cmd_drive (p); } } break; case HCAN_HES_TASTER_DOWN: // Nur im 1-Taster-Betrieb verwendet if (is_group_in_rolladen(p, frame->data[2])) { if (p->mute || p->blockingTimer) return; // Befehl abblocken if (p->power) { p->change_dir_counter = 7; // 0,7 s (1-Taster-Betrieb: Richtungswechsel, falls lange gedrueckt) rolladen_cmd_stop (p); // anhalten, falls der Rolladen faehrt } else { set_soll_laufzeit(p, p->last_dir); if (p->soll_laufzeit != -1) // liegt soll-Position bereits vor? rolladen_cmd_drive (p); } } break; case HCAN_HES_TASTER_UP: // Nur im 1-Taster-Betrieb verwendet if (is_group_in_rolladen(p, frame->data[2])) p->change_dir_counter = -1; // abmelden (1-Taster-Betrieb) break; case HCAN_HES_ROLLADEN_DEFINE_POSITION: { // Da die Rolladen keine Rueckmeldung geben, wo sie // gerade stehen, kann im Service-Falle (z.B. bei einem // Firmware Upgrade die Position der Rollaeden vorher // mit HCAN_HES_ROLLADEN_POSITION_REQUEST erfragt und // nach dem Upgrade mit HCAN_HES_ROLLADEN_DEFINE_POSITION // definiert werden. if (is_group_in_rolladen(p, frame->data[2])) { // Rolladenposition setzen: (pos+1) wegen Rundungsfehler p->laufzeit = (int32_t)(frame->data[3]+1) * p->config.laufzeit / 100; if (p->laufzeit > p->config.laufzeit) p->laufzeit = p->config.laufzeit; } } break; case HCAN_HES_ROLLADEN_POSITION_REQUEST: if (is_group_in_rolladen(p, frame->data[2])) { answer.data[1] = HCAN_HES_ROLLADEN_POSITION_REPLAY; answer.data[2] = frame->data[2]; answer.data[3] = rolladen_get_position(p); answer.size = 4; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); } break; } if (p->config.mute == frame->data[2]) { if (HCAN_HES_MUTE_OFF == frame->data[1]) p->mute = 0; // Rolladen aktiv else if (HCAN_HES_MUTE_ON == frame->data[1]) p->mute = 1; // Rolladen passiv (per Taster nicht verfahrbar) } }
void heizung_can_callback(device_data_heizung *p, const canix_frame *frame) { canix_frame answer; answer.src = canix_selfaddr(); answer.dst = frame->src; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_HES; switch (frame->data[1]) { case HCAN_HES_1WIRE_TEMPERATURE : if (frame->data[2] == p->config.sensor_id) { // we have a heizung and a temp sensor frame // now look if if fits to the heizung // temperature is a fixed point number mit 4 LSB Bits int16_t sensor_temp = frame->data[3] << 8 | frame->data[4]; // store the measure value p->measure_value = sensor_temp; p->received_interval_counter = 0; } break; case HCAN_HES_HEIZUNG_SET_MODE_OFF : if (p->config.id == frame->data[2]) p->mode = HEIZUNG_MODE_OFF; break; case HCAN_HES_HEIZUNG_SET_MODE_MANUAL : if (p->config.id == frame->data[2]) { p->mode = HEIZUNG_MODE_MANUAL; p->manual_rate = frame->data[3]; p->duration_counter = (frame->data[4] << 8) | frame->data[5]; } break; case HCAN_HES_HEIZUNG_SET_MODE_THERMOSTAT_DETAILS : if (p->config.id == frame->data[2]) { p->mode = HEIZUNG_MODE_THERMOSTAT; p->thermostat_temp = (frame->data[3] << 8) | frame->data[4]; p->duration_counter = (frame->data[5] << 8) | frame->data[6]; } break; case HCAN_HES_HEIZUNG_SET_MODE_AUTOMATIK: if (p->config.id == frame->data[2]) p->mode = HEIZUNG_MODE_AUTOMATIK; break; case HCAN_HES_HEIZUNG_DETAILS_REQUEST : { if (p->config.id == frame->data[2]) { switch (p->mode) { case HEIZUNG_MODE_OFF : answer.data[1] = HCAN_HES_HEIZUNG_MODE_OFF_DETAILS; answer.data[2] = p->config.id; answer.size = 3; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); break; case HEIZUNG_MODE_MANUAL : answer.data[1] = HCAN_HES_HEIZUNG_MODE_MANUAL_DETAILS; answer.data[2] = p->config.id; answer.data[3] = p->manual_rate; answer.data[4] = p->duration_counter >> 8; answer.data[5] = p->duration_counter; answer.size = 6; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); break; case HEIZUNG_MODE_THERMOSTAT : answer.data[1] = HCAN_HES_HEIZUNG_MODE_THERMOSTAT_DETAILS; answer.data[2] = p->config.id; answer.data[3] = p->thermostat_temp >> 8; answer.data[4] = p->thermostat_temp; answer.data[5] = p->duration_counter >> 8; answer.data[6] = p->duration_counter; answer.size = 7; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); break; case HEIZUNG_MODE_AUTOMATIK : { int8_t index; index = heizung_get_matching_zeitzone_index(p); if (index != -1) { // we got an zeitzone which matches int16_t master_value = 0; solltemp_line_t *zeitzone = (solltemp_line_t *) &(p->config.zeitzone0_id); master_value = zeitzone[index].temp; answer.data[1] = HCAN_HES_HEIZUNG_MODE_AUTOMATIK_DETAILS; answer.data[2] = frame->data[2]; answer.data[3] = master_value >> 8; answer.data[4] = master_value; answer.data[5] = heizung_get_matching_zeitzone_id(p); answer.size = 6; } else { canix_syslog_P(SYSLOG_PRIO_ERROR, PSTR("zeitzone: no match!")); answer.data[1] = HCAN_HES_HEIZUNG_MODE_AUTOMATIK_DETAILS; answer.data[2] = frame->data[2]; answer.data[3] = 0; answer.data[4] = 0; answer.data[5] = 0; answer.size = 6; } canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); } break; } } }
void lichtzone_can_callback(device_data_lichtzone *p, const canix_frame *frame) { switch (frame->data[1]) { case HCAN_HES_TASTER_DOWN : { uint8_t i; uint8_t *toggle_group; uint8_t *off_group; uint8_t *on_group; // fuer extended on Modus: if (p->exton_sec_counter == 0) { p->exton_sec_counter = 1; } p->exton_taster_down_counter++; // ueber alle 4 Toggle Gruppen iterieren toggle_group = (uint8_t *) &(p->config.toggle_gruppe0); for (i = 0; i < 4; i++) { if (frame->data[2] == toggle_group[i]) { // Pruefen, ob in den ext on Modus geschaltet werden soll: if ((p->exton_taster_down_counter >= 3) && (p->exton_sec_counter > 0) && (p->exton_sec_counter < LICHTZONE_EXT_SEC_COUNTER_MAX)) { p->exton_sec_counter = 0; p->exton_taster_down_counter = 0; p->state = LICHTZONE_STATE_ON_EXT; p->timer_counter = LICHTZONE_EXT_TIMERINIT; inform_action_groups(p); // ganz rausspringen, damit innerhalb der naechsten Interation der Schleife // nicht den State wieder zurueckgestetzt wird! return; } // Normaler Modus: wenn Timer aktiviert... if (p->config.timer_delay) { switch (p->state) { case LICHTZONE_STATE_OFF : lichtzone_setup_timer(p); p->state = LICHTZONE_STATE_ON; inform_action_groups(p); break; case LICHTZONE_STATE_ON : lichtzone_setup_timer(p); break; case LICHTZONE_STATE_ON_EXT : p->state = LICHTZONE_STATE_OFF; p->exton_sec_counter = 0; p->exton_taster_down_counter = 0; p->timer_counter = 0; inform_action_groups(p); break; } } // Normaler Modus: wenn kein Timer aktiviert... else { switch (p->state) { case LICHTZONE_STATE_OFF : p->state = LICHTZONE_STATE_ON; break; case LICHTZONE_STATE_ON : p->state = LICHTZONE_STATE_OFF; break; case LICHTZONE_STATE_ON_EXT : p->state = LICHTZONE_STATE_OFF; break; } inform_action_groups(p); } } } // wenn eine Off-Gruppe passt, die Action Gruppen // informieren. Das geschieht unabhaengig vom Status; // denn damit ist eine globale Haus-Licht-Aus-Funktion // realisierbar off_group = (uint8_t *) &(p->config.off_gruppe0); for (i = 0; i < 2; i++) { if ((frame->data[2] == off_group[i])) { p->state = LICHTZONE_STATE_OFF; p->timer_counter = 0; inform_action_groups(p); } } // wenn eine On-Gruppe passt, die Action Gruppen // informieren. Das geschieht unabhaengig vom Status; // denn damit ist eine globale Haus-Licht-An-Funktion // realisierbar on_group = (uint8_t *) &(p->config.on_gruppe0); for (i = 0; i < 2; i++) { if ((frame->data[2] == on_group[i])) { p->state = LICHTZONE_STATE_ON; // If it has a timer, reset the timer: if (p->config.timer_delay) lichtzone_setup_timer(p); inform_action_groups( p); } } } break; case HCAN_HES_POWER_GROUP_ON : { // schauen, ob eine der Action Groups passt; falls // ja, internen Status updaten und ggfls Timer starten uint8_t *action_group; uint8_t i; action_group = (uint8_t *)&(p->config.action_gruppe0); for (i = 0; i < 2; i++) { if ((action_group[i] != 255) && (action_group[i] == frame->data[2])) { switch (p->state) { case LICHTZONE_STATE_OFF : case LICHTZONE_STATE_ON : p->state = LICHTZONE_STATE_ON; if (p->config.timer_delay) lichtzone_setup_timer(p); // inform_action_groups(..) entfaellt, da // wir ja eine Botschaft, die direkt an die // Action group ging, abgefangen haben. Daher // haben wir "nur" den State aktualisiert. break; case LICHTZONE_STATE_ON_EXT : // in diesem Falls nichts machen! break; } } } } break; case HCAN_HES_POWER_GROUP_OFF : { // schauen, ob eine der Action Groups passt; falls // ja, internen Status updaten uint8_t *action_group; uint8_t i; action_group = (uint8_t *)&(p->config.action_gruppe0); for (i = 0; i < 2; i++) { if ((action_group[i] != 255) && (action_group[i] == frame->data[2])) { p->state = LICHTZONE_STATE_OFF; p->timer_counter = 0; // inform_action_groups(..) entfaellt, da // wir ja eine Botschaft, die direkt an die // Action group ging, abgefangen haben. Daher // haben wir "nur" den State aktualisiert. break; } } } break; case HCAN_HES_POWER_GROUP_TIMER_QUERY : { canix_frame answer; uint8_t *action_group; uint8_t i; action_group = (uint8_t *)&(p->config.action_gruppe0); for (i = 0; i < 2; i++) { if (action_group[i] == frame->data[2]) { answer.src = canix_selfaddr(); answer.dst = frame->src; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_HES; answer.data[1] = HCAN_HES_POWER_GROUP_TIMER_REPLAY; answer.data[2] = action_group[i]; answer.data[3] = p->timer_counter >> 8; answer.data[4] = p->timer_counter & 0xff; answer.size = 5; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); break; } } } break; case HCAN_HES_POWER_GROUP_SET_TIMER : { uint8_t *action_group; uint8_t i; action_group = (uint8_t *)&(p->config.action_gruppe0); for (i = 0; i < 2; i++) { if (action_group[i] == frame->data[2]) { p->timer_counter = (frame->data[3] << 8) | frame->data[4]; break; } } } break; }