Forum: Projekte & Code Sipdial per ESP8266 an Fritzbox


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Jürgen L. (temp1234)


Angehängte Dateien:

Bewertung
3 lesenswert
nicht lesenswert
Christion T. hat neulich im Beitrag:
Beitrag "Türklingel per ESP32 (WLAN, SIP) an Fritzbox"

den Code für seine ESP Klingel veröffentlicht. Das hat mich dazu 
gebracht auch mal wieder etwas in dieser Richtung zu machen. Allerdings 
benötige ich den Code um per Sip die Fritzbox klingeln zu lassen 
ausdrücklich nicht in Verbindung mit dem ESPxxx. Bisher mache ich das 
über einen Asterisk-Server der auf meinem NAS läuft. Nun soll so etwas 
in den Code meines selbst geschriebenen Servers für die Heimautomation. 
Allerdings ist Christians Code zu sehr von der ESP Infrastruktur 
abhängig. Das Anzupassen kommt einer Neuentwicklung gleich. Das habe ich 
dann gemacht. Im angehängten Code ist eine C++ Classe Sip enthalten die 
bis auf die Funktionen Sip::SendUdp(), Sip::Random(), Sip::Millis()und 
Sip::MakeMd5Digest() Plattform unabhängig ist. Entwickelt habe ich das 
als Windows-Konsolen Programm. Das kann ich aber aus lizensrechtlichen 
Gründen nicht veröffentlichen. Deshalb hier das ganze als Arduino ino 
für den Esp8266.
Das ist wohl gemerkt kein fertiges Projekt für ahnungslose Bastler. Es 
ist nur als Demo zu verstehen. Nach dem Reset und Connecten an die 
Fritzbox wählt der ESP die festgelegte Nummer und legt sich dann nach 
15s in den Tiefschlaf.
Wer etwas sinnvolles damit machen will, muss den Rest dann noch selbst 
entwickeln.
Ich selbst nutze die Arduino IDE nicht, sondern eine makefile Umgebung 
wie ich sie heir schon mal beschrieben haben.
Beitrag "Re: ESP32 & ESP8266 etc ohne Arduino?"

Der gesamte Code der Sip-Klasse kommt ohne dynamischen Speicher aus. Es 
wird nur ein char Buffer für das Zusammenbauen der UDP Packete benötigt, 
den ich selbst nicht in der Klasse halte. Zu beachten ist weiterhin, 
dass sich die Klasse die Konfigurationsdaten die in der init-Funktion 
übergeben werden nicht buffert, die Pointer müssen deshalb über die 
Laufzeit gültig bleiben. Bei meiner Fritzbox kommt es oft vor, dass das 
erste UDP-Packet irgendwie verloren geht. Im Gegensatz zu Christians 
Code versuche ich das INVITE zu wiederholen wenn die Fritzbox nicht 
antwortet.

von Marc G. (marcm)


Bewertung
0 lesenswert
nicht lesenswert
Danke,

nachdem auskommentieren/einkommentieren des return-werts in der 
Sip::Random() Funktion wegen folgendem Fehler :
sipdial.ino: In member function 'uint32_t Sip::Random()':

sipdial:471: error: 'secureRandom' was not declared in this scope

   return secureRandom(0x3fffffff);


exit status 1
'secureRandom' was not declared in this scope

funktioniert dein Aduino-Sketch auf meiner NodeMCU. Auch wenn ich noch 
hier drüber gestolpert bin und der Fehler anscheinend im Fritz!OS 6.83 
meiner 7390 immernoch nicht behoben ist... :
https://www.heise.de/forum/heise-online/News-Kommentare/AVM-veroeffentlicht-Fritz-OS-6-60/Seit-6-60-keine-Anmeldung-von-SIP-Nebenstelle-moeglich/posting-28864356/show/

Grüße
Marc

von Jürgen L. (temp1234)


Bewertung
0 lesenswert
nicht lesenswert
Marc G. schrieb:
> nachdem auskommentieren/einkommentieren des return-werts in der
> Sip::Random() Funktion wegen folgendem Fehler :

Du solltest mal deine Entwicklungsumgebung aktualisieren. Aktuell ist 
Arduino ESP bei 2.4. Die Funktion war auch in 2.3 schon drin.

Du solltes aber besser nicht das auskommentierte Standard rand() 
verwenden ohne einen srand() mit einem zufälligen Wert. Anderenfalls 
erzeugt die rand() Funktion nach jedem Reset die gleichen Zahlen, was 
bei dieser Anwendung nicht besonders gut ist. Hier die Funktion wie sie 
in neueren Esp-Arduinos enthalten ist und die Hardware des ESP8266 
nutzt:
#define RANDOM_REG32  ESP8266_DREG(0x20E44) 
long secureRandom(long howbig) {
    if(howbig == 0) {
        return 0;
    }
    return RANDOM_REG32 % howbig;
} 

Marc G. schrieb:
> Auch wenn ich noch
> hier drüber gestolpert bin und der Fehler anscheinend im Fritz!OS 6.83
> meiner 7390 immernoch nicht behoben ist... :

Damit hat mich AVM auch schon zur Weißglut gebracht. Erst gingen kurze 
Passwörter nicht mehr, in aktuellen Firmware-Versionen auch keine kurzen 
Usernamen mehr. Es gab mal einen Stand, da musste man alle! 
Telefongeräte löschen, danach die Fritzbox zwingend neu starten und erst 
danach konnte man sie wieder einrichten. Das war bei mir zu Hause und 
bei beiden Fritzboxen in der Firma nachvollziehbar.

von Marc G. (marcm)


Bewertung
0 lesenswert
nicht lesenswert
Jürgen L. schrieb:
> Du solltest mal deine Entwicklungsumgebung aktualisieren. Aktuell ist
> Arduino ESP bei 2.4. Die Funktion war auch in 2.3 schon drin.

Ja das ist bestimmt der Grund. Es war eine alte Arduino 1.6.8 IDE mit 
der ESP 2.0 Bibliothek im Einsatz

Danke schön

Marc

: Bearbeitet durch User
von Harald P. (haraldp)


Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für das schön schlanke Programm. Bei mir hat es - nach 
Anpassen auf meine Umgebung - sofort funktioniert. Ich wußte gar nicht, 
daß man das SIP-Protokoll auch mit Udp machen kann. Damit geht es m.E. 
viel einfacher als mit Tcp.
Harald

von Jürgen L. (temp1234)


Bewertung
0 lesenswert
nicht lesenswert
Eigentlich ist bei Sip UDP Standard. Das macht es auch immer etwas 
komplizier wenn Router dazwischen sind.
Das Programm ist deshalb relativ schlank, weil ich nicht versucht habe 
das Protokoll komplett zu implementieren. Es ist auch nicht angedacht 
irgendwelche Audio-Daten zu verarbeiten. Allerdings kann man immerhin 
die Tastencodes des angerufenen Telefons abgreifen wenn man das will.

von Obi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Demo,  es funktioniert bei mir wie geplant. Ich bin 
relativ unerfahren in der Progarmmierung in C, deswegen bitte ich etwas 
um Verständnis für mein "Unverständnis"

Ich möchte ich einen Sip-Dial bei einem Druck eines Tasters auslösen, 
der ESP8266 soll anschließend nicht in den DeepSleep fallen sondern auf 
die nächste Betätigung warten.

Hat jemand einen Tipp für mich an welcher Stelle ich die Aktion auf die 
Tasterbetätigung einfüge? Das ganze muss ja auch im loop funktionieren 
so dass ständig der Pin abgefragt wird.

Obi

von Nicki (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo ,

Ich finde die sip Türklingel echt gut
habe aber Probleme , vielleicht kann mir jemand helfen ?.

ich würde gerne den klingel Aufruf per void aufrufen
beispiel : wenn Taster gedrückt dann 3 Sekunden klingeln.

ich hab es versucht zu machen , hab es aber nicht hinbekommen.

wenn ich den loop in einen Unterprogramm packe , klingelt es unendlich.
leider verstehe ich das Programm nicht.

Bitte um Hilfe !

Danke.

von Nicki (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Endlich !

Hab ich es hinbekommen ,
ich habe alle seriellen Debug ausgaben entfernt.
abfrage zwei taste , wenn taste gedrückt ---> meldung
Kein Deep Standby


viel Spass damit

Grüße Nicki

von Veit D. (devil-elec)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

eine Frage dazu. Die Fritzbox wird hier rein per WLAN kontaktiert?
TR064 muss in der Fritzbox nicht aktiviert werden? Oder doch?
Danke im voraus.

von Marc G. (marcm)


Bewertung
0 lesenswert
nicht lesenswert
Der ESP wird hier als IP-Telefoniegerät an der Fritzbox angemeldet. 
Sonst muss da nichts weiter gemacht werden

Marc

von Hegel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Marc G. schrieb:

> Der ESP wird hier als IP-Telefoniegerät an der Fritzbox angemeldet.
> Sonst muss da nichts weiter gemacht werden


Kann das eine Einfallstor für Hacker sein?

Siehe Artikel auf Heide.de:

https://www.heise.de/newsticker/meldung/Bundesnetzagentur-stoppt-Abzocke-durch-Router-Hacking-4282164.html

von Veit D. (devil-elec)


Bewertung
0 lesenswert
nicht lesenswert

von Veit D. (devil-elec)


Bewertung
0 lesenswert
nicht lesenswert
Marc G. schrieb:
> Der ESP wird hier als IP-Telefoniegerät an der Fritzbox angemeldet.
> Sonst muss da nichts weiter gemacht werden
>
> Marc

aha, sehr schön. Weil das Bsp. aus der c't 17/2018 nutzt TR064 und das 
muss erst aktiviert werden. Mit Raspi c't 17/2017 hatte ich es damals 
zum laufen bekommen.

: Bearbeitet durch User
von Christian S. (schmitze)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

tolles Projekt ! Welchen 8266 habt Ihr denn dafür genommen und was als 
Akku und wie lange hält der ? Und wie lange dauert es, bis vom Klingeln 
am Tor dann die Telefone klingeln ?

Grüße

Christian

von Michael (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin noch am Überlegen, ob ich das Ganze mit einem Pi oder ESP machen 
soll.
Ich möchte allerdings zwei Klingel (Zweifamilienhaus) unterstützen.#
Dazu bräuchte ich dann aber 2 ESPs, oder?

Gruß
Michael

von Christian S. (schmitze)


Bewertung
0 lesenswert
nicht lesenswert
...noch eine Frage: Wie wird der EPS denn geschaltet ? Nur mit dem 
klingeltaster an den Akku wird ja nicht reichen oder ? Ich würde den 
gerne am Tor draussen anbringen, weil die Funkklingel dort funktioniert 
meist nicht

von Schmitze (Gast)


Bewertung
0 lesenswert
nicht lesenswert
...ich beantworte meine Fragen mal einfach selber, nachdem ich das ans 
Laufen bekommen habe:
ESP an Akku, Klingeltaster an GND und Reset. Zeit zwischen drücken des 
Tasters und Anfang Klingeln der Telefone nur ca. 1s !!! Sehr cool !!!

von Meister Kleister (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mir gefällt die hier vorgestellt Lösung sehr gut, zusammen mit der 
Schaltung aus dem heise-Artikel funktioniert sie nach Eingabe der 
Zugangsdaten ohne Änderungen auf anhieb. Allerdings hört das klingeln 
nicht auf, wenn man den ESP komplett vom Strom trennt, ohne das Ende des 
15 Sekunden Programmzyklus abzuwarten.

Die Fritzbox klingelt allein mit ausgeschaltetem ESP munter weiter. Gibt 
es dafür eine passende Einstellung in der Fritzbox oder kann man den 
abgesetzten Befehl anpassen. Ich nutze den Rundruf (const char 
*sipdialnr   = "**9";) als Klingelzeichen.

Zum Thema Sicherheit: Man kann in der Fritzbox dem ESP dem Zugang vom 
oder ins Internet verbieten. Man kann in der SIP-Telefon-Konfiguration 
in der Fritzbox eine leere/keine Nummer für eingehende Nummern zuweisen 
und man kann alle ausgehenden Nummern abwählen. Der interne Ruf "**9" 
funktioniert weiterhin. Damit ist der ESP vor Einflüssen aus der Ferne 
relativ sicher. Im ESP ist nur das WLAN-Passwort und die Sipzugangsdaten 
gespeichert. Anders als bei der Heise-Klingel-Anleitung 
(https://shop.heise.de/katalog/esp-uberallklingel), bei  der zusätzlich 
das kritische Admin-Passwort auf dem ESP unverschlüsselt gespeichert 
werden muss.

von Meister Kleister (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Nochwas: Man kann in der Fritzbox eine "IP-Türsprechanlage" einrichten. 
Die unterstütz zum einen mehrere Klingeln, zum anderen kann man eine 
Code festlegen, mit dem sich die Türen öffnen lassen würden. Außerdem 
ist bereits die Telefonierfunktion in der Standardkonfiguration 
begrenzt.

Leider scheint das unaufhörliche Klingeln bei spontaner 
Stromunterbrechung ein Problem von SIP oder der Fritzbox zu sein. Auch 
mit einem Softwarephone, bei dem plötzlich die Netzverbindung getrennt 
wird, stoppt das Klingeln nicht von allein.

von Hilgi (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Moin,


es funktioniert im Prinzip auf Anhieb! :)
Sehr toll, danke für diese Einführung.

Was nicht funktioniert, ist der Text den man übergibt.
An allen Endgeräten( DECT, ANALOG, WLAN ) erscheint im Display wahlweise 
die
"**621" oder "ESP8266_TEST", in keinem Fall ist die von mir im Code 
eingegebene Nachricht "TESTER" zu lesen.

In deinem Protokoll, stellst du dies so dar:
 AddSipLine("From: \"%s\"  <sip:%s@%s>;tag=%010u", pDialDesc, pSipUser, 
pSipIp, tagid);

Sonst funktioniert ja alles, dennoch frage ich mich -> wieso geht das 
nicht und wo is der Text geblieben? Ich kann den ja nirgends abfassen, 
theoretisch könnte/müsste man den ja dann aus Dial entfernen, wenn der 
eh nichts bringt...

Oder übersehe ich da was?


Grüße :)

von Meister Kleister (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Im DECT-Handteil werden die Namen so angezeigt, wie sie in der Fritzbox 
hinterlegt sind. Bei dir ist das wahrscheinlich "**621" [kein Name] oder 
"ESP8266_TEST". Der Sip-Name wird angezeigt, wenn dein Empfangsgerät die 
Sip-Daten auswertet. Ist bei mir mit einem Soft-Phone (PhoneLite) auf 
dem PC so, das wie der ESP als SIP-Telefon eingerichtet ist.

von Alois N. (alois)


Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Ich habe eine kleine Platine entwickelt die in ein Siedle Haustelefon 
HT-511 passt. Wer Lust hat, kann die Schaltung gerne nachbauen.

Die Schaltung besteht aus einem AC/DC Netzteil das die 12V 
Wechselspannung in ca. 3,3V Gleichspannung zur Versorgung des ESP8285 
ESP-1 Moduls wandelt. Außerdem sitzen zwei AC-Optokoppler auf der 
Platine zur Abfrage von zwei Klingeltastern (getrennte Eingänge). 
Aufgrund der besseren Reichweite habe ich ein ESP8285 ESP-1 WLAN 
Funkmodul verwendet.

Die Versorgungsspannung habe ich an die Klemmen b und c des Siedle 
Haustelefons HT-511 angeschlossen. Den Eingang habe ich parallel an das 
Läutwerk (Summer) am Siedle Haustelefon HT-511 geklemmt.

Den Code habe ich von @Nicki verwendet:
https://www.mikrocontroller.net/attachment/371951/sip_klingel_ND.ino

Funktioniert prima :-)

von Andreas G. (djmetro)


Bewertung
0 lesenswert
nicht lesenswert
Hi, hast du zufällig noch eine Platine übrig? Würde mich sehr 
interessieren.

von Alois N. (alois)


Bewertung
0 lesenswert
nicht lesenswert
Andreas G. schrieb:
> Hi, hast du zufällig noch eine Platine übrig? Würde mich sehr
> interessieren.

Ja, hab ich. Du hast eine Nachricht von mir bekommen.

Grüße :)

von Alois N. (alois)


Angehängte Dateien:

Bewertung
2 lesenswert
nicht lesenswert
Ich habe den Code von Nicki erweitert und eine Türöffner-Funktion mit 
implementiert.

Wenn man einen Anruf von der Tür entgegen nimmt, wird das Drücken einer 
beliebigen Taste am Telefon jetzt erkannt.

Im SIP INFO-Paket steht die gedrückte Taste direkt im Klartext. Das 
Parsen und das Auslösen einer Aktion der Taste wurde im Code 
hinzugefügt.

Im Beispiel verwende ich als Ausgang GPIO14 für den Türöffner und die 
Taste "6" am Telefon zum Auslösen des Türöffners. Die Einschaltzeit für 
den Türöffner lässt sich ebenfalls einstellen.

von Roger Z. (microplayer)


Bewertung
0 lesenswert
nicht lesenswert
Vielleicht hilft es jemandem -
Ich versuche den Sketch auf ESP32 zu portieren (mit beschränktem 
Vorwissen) und nutze dabei die aktuelle (Mai 2019) Arduino IDE samt den 
aktuellen ESP32 1.0.1 Libraries.

Mir gelang es leider nicht, die originale Zeilen

// generate a 30 bit random number
uint32_t Sip::Random()
{
  // return ((((uint32_t)rand())&0x7fff)<<15) + 
((((uint32_t)rand())&0x7fff));
  return secureRandom(0x3fffffff);
}

gegen den ESP32 kompiliert zu bekommen, denn ich finde keine passende 
Library, die secureRandom() per #include für den ESP32 nutzbar macht.

Der ESP32 hat aber einen HW RND Generator, den man per esp_random(void) 
nutzt. Und so wird daraus:
// generate a 30 bit random number
uint32_t Sip::Random()
{
   return esp_random();
}
Damit kommt der Compiler jedenfalls klar.

Mein Bitte: Kann  einer der Wissenden hier bestätigen, dass esp_random() 
hier richtig eingesetzt ist? Ich freue mich auch über Hinweise, wie ich 
secureRandom() auf dem ESP32 doch noch ans Fliegen bekomme.

Danke vorab - Roger

von Roger Z. (microplayer)


Bewertung
0 lesenswert
nicht lesenswert
Beim Portieren des Sketches auf ESP32 scheitere ich mangels C++ 
Kenntnissen an folgernder Fehlermeldung bezüglich Typkonvertierung.
Kann mir da jemand auf die Sprünge helfen?
Wo gleiche ich mit dem wenigsten Aufwand und Risiko den Typ an? In der 
Definition, im Aufruf und welchen Typ nehme ich? Danke, Roger

--------------------------------------------------------------------
/Volumes/data/Meine Geräte/Arduino UNO/Roger Test/ESP32_SIP_Tuerklingel/ESP32_SIP_Tuerklingel.ino: In member function 'int Sip::SendUdp()':
ESP32_SIP_Tuerklingel:439:13: error: invalid conversion from 'char*' to 'const uint8_t* {aka const unsigned char*}' [-fpermissive]
   Udp.write(pbuf, strlen(pbuf));
             ^
In file included from /Users/roger/Library/Arduino15/packages/esp32/hardware/esp32/1.0.1/libraries/WiFi/src/WiFi.h:39:0,
                 from /Volumes/data/Meine Geräte/Arduino UNO/Roger Test/ESP32_SIP_Tuerklingel/ESP32_SIP_Tuerklingel.ino:1:
/Users/roger/Library/Arduino15/packages/esp32/hardware/esp32/1.0.1/libraries/WiFi/src/WiFiUdp.h:65:10: note:   initializing argument 1 of 'virtual size_t WiFiUDP::write(const uint8_t*, size_t)'
   size_t write(const uint8_t *buffer, size_t size);
          ^
Mehrere Bibliotheken wurden für "WiFi.h" gefunden
 Benutzt: /Users/roger/Library/Arduino15/packages/esp32/hardware/esp32/1.0.1/libraries/WiFi
 Nicht benutzt: /Applications/Arduino.app/Contents/Java/libraries/WiFi
Bibliothek WiFi in Version 1.0 im Ordner: /Users/roger/Library/Arduino15/packages/esp32/hardware/esp32/1.0.1/libraries/WiFi  wird verwendet
exit status 1
invalid conversion from 'char*' to 'const uint8_t* {aka const unsigned char*}' [-fpermissive]

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Das hier könnte funktionieren:
Udp.write((uint8_t *) pbuf, strlen(pbuf));

Sauberer wäre es, wenn pbuf vom Typ uint8_t* wäre, aber dann würde der 
Aufruf von strlen natürlich scheitern ...

von temp (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Roger Z. schrieb:
> // generate a 30 bit random number
> uint32_t Sip::Random()
> {
>   // return ((((uint32_t)rand())&0x7fff)<<15) +
> ((((uint32_t)rand())&0x7fff));
>   return secureRandom(0x3fffffff);
> }
>

wenn nichts hilft dann das auskommentierte benutzen:
return ((((uint32_t)rand())&0x7fff)<<15) + ((((uint32_t)rand())&0x7fff));
dann solltest du aber in der setup() folgenden Code anpassen:

...
  int i=0;
  for (i=0; i<100; i++)
    {
    if (WiFi.status() == WL_CONNECTED) 
      break;
    delay(100);
    Serial.print(".");
    }
...

ändern in:
 
  int i=0;
  for (i=0; i<10000; i++)
    {
    rand();
    if (WiFi.status() == WL_CONNECTED) 
      break;
    delay(1);
    if ((i%100)==0)
      Serial.print(".");
    }


Was für ein Random-Wert da am Ende herauskommt ist völlig egal. Nur wenn 
es immer der gleiche ist kommt die Fritzbox durcheinander. Da rand() 
nach dem Neustart aber gleiche Werte liefert ist das ein Problem. Mit 
der Änderung von oben wird der Wert davon abhängig wie lange der 
WLAN-Connect dauert. Das ist schon mal besser als nichts.

von temp (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Noch ein Hinweis. Den ESP32 an dieser Stelle zu benutzen mach nur Sinn, 
wenn der ESP32 nicht! in den Tiefschlaf geht. Die Zeit bis sich der 
ESP32 nach dem Reset wieder im WLAN befindet ist deutlich länger als 
beim ESP8622.
Für den Fall, dass sich der ESP32 dauerhaft im Betriebsmodus befindet 
geht das auch mit dem rand() ohne die Sonderbehandlung am Anfang, da 
dann der Zufallsgenerator nicht jedes mal mit dem Reset neu 
initialisiert wird.

von Temp1 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo, das hört sich alles sehr gut an, ich interessiere mich für deine 
Platine, hast Du noch eine übrig.
Grüße

von Peter G. (peter_geher)


Bewertung
0 lesenswert
nicht lesenswert
Aloha Freunde,
Ich hab mir das jetzt lauffähig für den ESP32 (In Verbindung mit einen 
Mikrofon-Modul) umgebogen. Sobald meine 1970er Rappel-Glocke rappelt, 
reagiert das Mikrofon und der ESP32 wählt **9. Soweit alles bestens.

Allerdings lässt der ESP32 so lange Klingeln bis jetzt abhebt. Hat 
jemand eine Idee, wie man eine Art Timeout einbauen kann, das



  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
  Udp.begin(sipport);
  aSip.Init(sipip, sipport, ip, sipport, sipuser, sippasswd, 15);
  aSip.Dial(sipdialnr, sipdialtext); // Dial

    digitalWrite(ledPin, HIGH); // Mikrofon schaltet HIGH
  } else {
 // nichts machen ...
    digitalWrite(ledPin, LOW);
   }

zB nach 10-15 Sekunden ESP-Seitig abgebrochen wird?

von temp (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Um zu sehen wo das bei dir klemmt musst du schon mehr Code posten. Die 
15 am Ende von aSip.Init ist die Zeit nach dem aufgelegt wird. Das kann 
aber nur funktionieren wenn in einer Schleife wie im Originalprogramm 
weiterhin ständig das aSip.HandleUdpPacket() gerufen wird solange bis 
aSip.IsBusy() true liefert und darüber hinaus noch ein paar Sekunden. Im 
Beispiel 2. Ich denke irgenwo da hast du was falsch gemacht.

Beitrag #5941086 wurde vom Autor gelöscht.
von Peter G. (peter_geher)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
temp schrieb:
> musst du schon mehr Code posten

Stimmt. Ich wusste doch, das ich etwas vergessen habe :-)

Habe das Konstrukt gerade vor mir liegen, wenn ich auf das Mikro tippe, 
geht die LED vom ESP auf HIGH und dial wird eingeleitet. Nur halt das 
Stoppen klappt (noch) nicht.

von temp (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Wenn du das Dial auch tausendfach aufrufst brauchst du dich nicht 
wundern dass deine Fritzbox durcheinander kommt.

//int deepSleepDelay=0;  
void loop(void) 
{
  int packetSize = Udp.parsePacket();
  if (packetSize>0)
    {
    caSipIn[0]=0;
    packetSize=Udp.read(caSipIn, sizeof(caSipIn));
    if (packetSize>0)
      {       
      caSipIn[packetSize]=0;
    #ifdef DEBUGLOG
      IPAddress remoteIp = Udp.remoteIP();
      Serial.printf("\r\n----- read %i bytes from: %s:%i ----\r\n", (int)packetSize, remoteIp.toString().c_str(), Udp.remotePort());
      Serial.print(caSipIn);
      Serial.printf("----------------------------------------------------\r\n");
    #endif
      }
    }
  aSip.HandleUdpPacket((packetSize>0) ? caSipIn : 0 );

  buttonState = digitalRead(buttonPin);

  // !!!!!!!! Das ist eine Endlos-Schleife oder mit anderen Worten solange 
  // dein Pin High ist wird das Init und Dial so oft ausgeführt wie der ESP        
  // kann. 
  // Ich hab das mal mit einer statischen Variablen geblockt aber nicht
  // getestet 
  static int bInDial=0;

  if (buttonState == HIGH) 
    {
    digitalWrite(ledPin, HIGH);
    if (!bInDial) 
      { 
      Udp.begin(sipport);
      aSip.Init(sipip, sipport, ip, sipport, sipuser, sippasswd, 2);
      aSip.Dial(sipdialnr, sipdialtext); // Dial
      bInDial=1;
      }
    }    
  else 
    {
    if (!aSip.IsBusy())
      bInDial=0; 

    // nichts
    digitalWrite(ledPin, LOW);
    }
}  


von Wolfgang (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Geniale Sache!

Auf der FritzBox ein weiteres IP-Telefon eingerichtet, die notwendigen 
Strings in der ino Datei angepasst und in einen WeMos D1 mini geflasht 
-> funktioniert.

So erspart man es sich gleich mit einer runden Himbeere auf Spatzen zu 
schießen;)

Vielen Dank für die ESP Portierung und Implementierung und das 
Veröffentlichen des Codes. Reset bis Anruf in ca. 1 bis 2s, Top.

von Manuel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

möchte meinen Türöffner mit einem Rückruf ansteuern, bräuchte dazu noch 
einen Lösungsansatz. Bin noch ein absoluter Anfänger in C, wäre um jede 
Hilfe dankbar.

Grüße

Manuel

von stieneker@web.de (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,
folgendes Problem:
Ich habe eine Klingelschaltung mit dem ESP8266 gebaut.
Der klingt sich in mein WLAN ein und klingelt die Telefone an.
Das ist das Programm von J.Liegner aus 2018.
Eigentlich funktioniert das auch gut.
Es gibt nur einen "Haken", wo ich nicht weiter weiss.

Die Schaltung wird über einen Reed-Relais mit "Selbsthaltung" aus dem 
ESP gesteuert.
Läuft also so:
1.Klingeltaster wird gedrückt,
2. Das reicht für kurze Zeit zum Start des ESP..
3. Das Programm läuft an und hält das Reed Relais.
4. Jetzt "klingelt" das Programm meine Telefone an.
5. Nach einer Zeit (bei mir 2 Minuten) fällt nach Inaktivität das Relais 
ab.

Jetzt zum Problem:
Es werden etwa 500 Zeilen mit Definitionen des Programms etc. Verbracht, 
bis das eigentliche Setup kommt, wo ich den Ausgang sinnvoll setzen kann 
(die Selbsthaltung).
Das ist oft zu lang, wenn nur kurz der Klingelknopf gedrückt wird.
 Wenn ich ganz vorne einen Loop (z.b. Start) einfüge wo ich das mache, 
fällt das Relais beim Verlassen des loops sofort ab ;(

Hat jemand eine Idee?
LG Manfred

von Alois N. (alois)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Manfred,

poste doch einfach mal deinen Source-Code um das ganze zu verstehen.

von Christian (Gast)


Bewertung
0 lesenswert
nicht lesenswert
...eigentlich kommt der Taster ja an Reset, wenn der gedrückt wird, 
resettet der ESP, klingelt die Telefone an und nach der vordefinierten 
Zeit geht der in den Deepsleep Modus. Ein Relais brauchst du da nicht...

von KeineFreundeHaber (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Moin

@Manfred
Findest Du Cross-posting toll oder uns, auf der anderen Seite des 
Universum, so schlimm?
Auch hier solltest Du den fragen der Anderen nachkommen - wenn Du Dich 
so zeigst, wie bei 'uns' - wird Das hier ebenfalls nicht sonderlich gut 
für Dich ausgehen.
Erschwerend kommt hinzu, daß Du hier sogar noch einen fremden Thread 
kaperst - aber so ist das Volk wohl heute.

Ach ja ... Cross-Post auf Arduino.cc
https://forum.arduino.cc/index.php?topic=648475.msg4373829#msg4373829

von temp (Gast)


Bewertung
0 lesenswert
nicht lesenswert
stieneker@web.de schrieb:
> Jetzt zum Problem:
> Es werden etwa 500 Zeilen mit Definitionen des Programms etc. Verbracht,
> bis das eigentliche Setup kommt, wo ich den Ausgang sinnvoll setzen kann
> (die Selbsthaltung).

Das ist völliger Schwachsinn. Selbst wenn in der C++ Datei ein paar 
Millionen Zeilen davor stehen hat das überhaupt nichts zu sagen. Was der 
ESP vor dem setup() macht ist zuerst vom reinen Initalisierunsgcode 
abhängig der für den ESP nötig ist um überhaupt erst mal bis zur main() 
Methode zu kommen. Beim ESP gehört (m.W.n) auch dazu den Code aus dem 
externen Flash erst mal in den RAM zu kopieren. Das kann sicher etwas 
dauern. Sämtliche C++ Kontruktoren werden auch vor der main() gerufen. 
Was der Arduino-Code ab main() bis zum setup() macht kannst du in den 
Arduino Quellen nachlesen. Der her verlinkte Code benötigt jedenfalls 
weniger als 1µs für die Intitialisiering von einigen wenigen variablen.
Eventuell könnte es helfen eine spezielle C++ Klasse zu schreiben in 
deren Konstruktor der Pin für die Selbsthaltung gesetzt wird. Der 
GPIO-Port muss dazu sicher auch erst mal initialisiert werde. Und das 
alles mit der ESP-Api und nicht mit Arduino, das dürfte zu dem Zeitpunkt 
noch nicht initialisiert sein. Ob das jetzt zeitlich was bringt kriegst 
du aber nur mit probieren raus.
Die Hardware kann dir auch einen Strich durch die Rechnung machen. Der 
ESP benötigt ja nicht unbedingt kleine Elkos, die müssen auch erst mal 
ab Tastendruck geladen werden.

von Christian (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Also, wie beschrieben, Reset drücken, ca. 1s später klingeln die 
Telefone für ca. 15s, bzw. Bis einer abnimmt, dann deepsleep bis zum 
nächsten Köingelknopf (tatsächlich der Resettaster) drücken. Flutscht 
wie doof, out of the box aus dem Thread(code)...

Grüsse Christian

von Nico .. (nico123)


Bewertung
0 lesenswert
nicht lesenswert
Klasse Projekt, vielen Dank an Jürgen und alle Beteiligten!

Ein Problem habe ich dabei aber: wird die Klingel und damit der Reset 
mehrmals betätigt innerhalb der 15s, dann klingelt die Fritzbox ewig!
Gibts da eine Lösung?

Danke und Grüße, Nico

von temp (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Eventuell den Reset-Pin mit einem GPIO-Pin auf High klemmen.
Die Widerstände hängen natürlich von deinem ESP-Board und dessen 
Reset-Beschaltung ab.

von Michael R. (michael_r233)


Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich ahbe das original Script genommen und auf einen ESp geflasht. 
Funktioniert grundsätzlich.
Leider klingelt das Ding immer mal ohne das der Taster gedrückt wird.
Und ab und zu regaiert es nicht. Nach aab und wieder anstöpseln des 
Stroms geht es dann erstmal wieder.
Hat jemand von euch auch noch dieses Problem?
Ich habe es mit dauerstrom, usb netzteil und mit Batteriepack versucht.

Danke und Gruß
Michael

von Alois N. (alois)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

poste mal den Aufbau deiner Schaltung.

Gruß Alois

von Michael R. (michael_r233)


Bewertung
0 lesenswert
nicht lesenswert
Aufbau der Schaltung.... hmm. Ich bin elektronisch nicht mit viel Wissen 
bestückt. Falls das folgende nicht reicht, bitte genauer erklären was du 
brauchst :)

Ich habe einfach einen Anpro ESP8266 microcontroller ESP-12E WiFi 
bestellt, mir Arduino runtergeladen und das Ding geflasht.
Der Klingeldraht überbrückt G und D6.
Geändert im Script habe ich nur:

if (digitalRead(12) == LOW) {
    //aSip.Dial("**9", "GPIO D6 !");
    aSip.Dial("**610", "Klingel Tor");
  }

wie gesagt geht das eigentlich ganz gut. Nur Ausfälle und Klingeln ohne 
Tasterdruck ab und zu.

von Alois N. (alois)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

mit Klingeldraht meinst Du die 9 - 12 Volt Klingelspannung vom 
Klingeltaster oder ist der Taster direkt zwischen GND und dem Eingang D6 
angeschlossen (potential getrennt)?

Gruß Alois

von Michael R. (michael_r233)


Bewertung
0 lesenswert
nicht lesenswert
Direkt angeschlossen, potentialfrei

von Alois N. (alois)


Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen Michael,

poste mal deinen Source-Code

Gruß Alois

von temp (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Michael R. schrieb:
> if (digitalRead(12) == LOW) {
>     //aSip.Dial("**9", "GPIO D6 !");
>     aSip.Dial("**610", "Klingel Tor");
>   }

Und das in der loop()? Wundert mich jetzt dass da überhaupt was geht. 
Aber selbst wenn man wenig Ahnung von Elektronik hat sollte man seinen 
Kopf einschalten oder es lassen.

von Michael R. (michael_r233)


Bewertung
0 lesenswert
nicht lesenswert
Das ist der Original code von Jürgen Liegner. Nur meine Daten 
eingetragen und die Nummer anstatt dem Sammelruf **9 in meine ganz unten 
im Script verändert.
/* ====================================================================

   Copyright (c) 2018 Juerge Liegner  All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the
      distribution.

   3. Neither the name of the author(s) nor the names of any contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   SUCH DAMAGE.
   
   
   
  
   ====================================================================*/

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#define DEBUGLOG

//------------------------------------------------
// configuration with fix ip
//------------------------------------------------

// wlan param
const char* ssid        = "xxxxxx";
const char* password    = "xxxxxxxxxxxxxx";

// sip params
const char *sipip       = "192.168.178.1"; // IP der FritzBox
int         sipport     = 5060;          // Port so lassen
const char *sipuser     = "xxxxxxxxxxx"; // Benutzername SIP-Call FritzBox
const char *sippasswd   = "xxxxxxxxxxx";  // Passwort SIP-Call FritzBox

// dial params
const char *sipdialnr   = "**701";////unten auskomentiert
const char *sipdialtext = "Türklingel";////unten auskomentiert

// network params
const char *ip          = "192.168.178.150";   // Eigene IP vom ESP
const char *gw          = "192.168.178.1";    //Gateway
const char *mask        = "255.255.255.0";  //Subnetmask
const char *dns         = "192.168.178.1";    // DNS
//------------------------------------------------

//#define DEBUGLOG
WiFiUDP Udp;

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// hardware and api independent Sip class
//
/////////////////////////////////////////////////////////////////////////////////////////////////////

char set = 0;

class Sip
{
    char       *pbuf;
    size_t      lbuf;
    char        caRead[256];

    const char *pSipIp;
    int         iSipPort;
    const char *pSipUser;
    const char *pSipPassWd;
    const char *pMyIp;
    int         iMyPort;
    const char *pDialNr;
    const char *pDialDesc;

    uint32_t    callid;
    uint32_t    tagid;
    uint32_t    branchid;

    int         iAuthCnt;
    uint32_t    iRingTime;
    uint32_t    iMaxTime;
    int         iDialRetries;
    int         iLastCSeq;
    void        AddSipLine(const char* constFormat , ... );
    bool        AddCopySipLine(const char *p, const char *psearch);
    bool        ParseParameter(char *dest, int destlen, const char *name, const char *line, char cq = '\"');
    bool        ParseReturnParams(const char *p);
    int         GrepInteger(const char *p, const char *psearch);
    void        Ack(const char *pIn);
    void        Cancel(int seqn);
    void        Bye(int cseq);
    void        Ok(const char *pIn);
    void        Invite(const char *pIn = 0);

    uint32_t    Millis();
    uint32_t    Random();
    int         SendUdp();
    void        MakeMd5Digest(char *pOutHex33, char *pIn);

  public:
    Sip(char *pBuf, size_t lBuf);
    void        Init(const char *SipIp, int SipPort, const char *MyIp, int MyPort, const char *SipUser, const char *SipPassWd, int MaxDialSec = 10);
    void        HandleUdpPacket(const char *p);
    bool        Dial(const char *DialNr, const char *DialDesc = "");
    bool        IsBusy() {
      return iRingTime != 0;
    }
};

Sip::Sip(char *pBuf, size_t lBuf)
{
  pbuf = pBuf;
  lbuf = lBuf;
  pDialNr = "";
  pDialDesc = "";
}

bool Sip::Dial(const char *DialNr, const char *DialDesc)
{
  if (iRingTime)
    return false;

  iDialRetries = 0;
  pDialNr = DialNr;
  pDialDesc = DialDesc;
  Invite();
  iDialRetries++;
  iRingTime = Millis();
  return true;
}

void Sip::Cancel(int cseq)
{
  if (caRead[0] == 0)
    return;
  pbuf[0] = 0;
  AddSipLine("%s sip:%s@%s SIP/2.0",  "CANCEL", pDialNr, pSipIp);
  AddSipLine("%s",  caRead);
  AddSipLine("CSeq: %i %s",  cseq, "CANCEL");
  AddSipLine("Max-Forwards: 70");
  AddSipLine("User-Agent: sip-client/0.0.1");
  AddSipLine("Content-Length: 0");
  AddSipLine("");
  SendUdp();
}

void Sip::Bye(int cseq)
{
  if (caRead[0] == 0)
    return;
  pbuf[0] = 0;
  AddSipLine("%s sip:%s@%s SIP/2.0",  "BYE", pDialNr, pSipIp);
  AddSipLine("%s",  caRead);
  AddSipLine("CSeq: %i %s", cseq, "BYE");
  AddSipLine("Max-Forwards: 70");
  AddSipLine("User-Agent: sip-client/0.0.1");
  AddSipLine("Content-Length: 0");
  AddSipLine("");
  SendUdp();
}

void Sip::Ack(const char *p)
{
  char ca[32];
  bool b = ParseParameter(ca, (int)sizeof(ca), "To: <", p, '>');
  if (!b)
    return;

  pbuf[0] = 0;
  AddSipLine("ACK %s SIP/2.0", ca);
  AddCopySipLine(p, "Call-ID: ");
  int cseq = GrepInteger(p, "\nCSeq: ");
  AddSipLine("CSeq: %i ACK",  cseq);
  AddCopySipLine(p, "From: ");
  AddCopySipLine(p, "Via: ");
  AddCopySipLine(p, "To: ");
  AddSipLine("Content-Length: 0");
  AddSipLine("");
  SendUdp();
}

void Sip::Ok(const char *p)
{
  pbuf[0] = 0;
  AddSipLine("SIP/2.0 200 OK");
  AddCopySipLine(p, "Call-ID: ");
  AddCopySipLine(p, "CSeq: ");
  AddCopySipLine(p, "From: ");
  AddCopySipLine(p, "Via: ");
  AddCopySipLine(p, "To: ");
  AddSipLine("Content-Length: 0");
  AddSipLine("");
  SendUdp();
}

void Sip::Init(const char *SipIp, int SipPort, const char *MyIp, int MyPort, const char *SipUser, const char *SipPassWd, int MaxDialSec)
{
  caRead[0] = 0;
  pbuf[0] = 0;
  pSipIp = SipIp;
  iSipPort = SipPort;
  pSipUser = SipUser;
  pSipPassWd = SipPassWd;
  pMyIp = MyIp;
  iMyPort = MyPort;
  iAuthCnt = 0;
  iRingTime = 0;
  iMaxTime = MaxDialSec * 1000;
}

void Sip::AddSipLine(const char* constFormat , ... )
{
  va_list arglist;
  va_start( arglist, constFormat);
  uint16_t l = (uint16_t)strlen(pbuf);
  char *p = pbuf + l;
  vsnprintf(p, lbuf - l, constFormat, arglist );
  va_end( arglist );
  l = (uint16_t)strlen(pbuf);
  if (l < (lbuf - 2))
  {
    pbuf[l] = '\r';
    pbuf[l + 1] = '\n';
    pbuf[l + 2] = 0;
  }
}

// call invite without or with the response from peer
void Sip::Invite(const char *p)
{
  // prevent loops
  if (p && iAuthCnt > 3)
    return;

  // using caRead for temp. store realm and nonce
  char *caRealm = caRead;
  char *caNonce = caRead + 128;

  char *haResp = 0;
  int   cseq = 1;
  if (!p)
  {
    iAuthCnt = 0;
    if (iDialRetries == 0)
    {
      callid = Random();
      tagid = Random();
      branchid = Random();
    }
  }
  else
  {
    cseq = 2;
    if (   ParseParameter(caRealm, 128, " realm=\"", p)
           && ParseParameter(caNonce, 128, " nonce=\"", p))
    {
      // using output buffer to build the md5 hashes
      // store the md5 haResp to end of buffer
      char *ha1Hex = pbuf;
      char *ha2Hex = pbuf + 33;
      haResp = pbuf + lbuf - 34;
      char *pTemp = pbuf + 66;

      snprintf(pTemp, lbuf - 100, "%s:%s:%s", pSipUser, caRealm, pSipPassWd);
      MakeMd5Digest(ha1Hex, pTemp);

      snprintf(pTemp, lbuf - 100, "INVITE:sip:%s@%s", pDialNr, pSipIp);
      MakeMd5Digest(ha2Hex, pTemp);

      snprintf(pTemp, lbuf - 100, "%s:%s:%s", ha1Hex, caNonce, ha2Hex);
      MakeMd5Digest(haResp, pTemp);
    }
    else
    {
      caRead[0] = 0;
      return;
    }
  }
  pbuf[0] = 0;
  AddSipLine("INVITE sip:%s@%s SIP/2.0", pDialNr, pSipIp);
  AddSipLine("Call-ID: %010u@%s",  callid, pMyIp);
  AddSipLine("CSeq: %i INVITE",  cseq);
  AddSipLine("Max-Forwards: 70");
  // not needed for fritzbox
  // AddSipLine("User-Agent: sipdial by jl");
  AddSipLine("From: \"%s\"  <sip:%s@%s>;tag=%010u", pDialDesc, pSipUser, pSipIp, tagid);
  AddSipLine("Via: SIP/2.0/UDP %s:%i;branch=%010u;rport=%i", pMyIp, iMyPort, branchid, iMyPort);
  AddSipLine("To: <sip:%s@%s>", pDialNr, pSipIp);
  AddSipLine("Contact: \"%s\" <sip:%s@%s:%i;transport=udp>", pSipUser, pSipUser, pMyIp, iMyPort);
  if (p)
  {
    // authentication
    AddSipLine("Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"sip:%s@%s\", response=\"%s\"", pSipUser, caRealm, caNonce, pDialNr, pSipIp, haResp);
    iAuthCnt++;
  }
  AddSipLine("Content-Type: application/sdp");
  // not needed for fritzbox
  // AddSipLine("Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
  AddSipLine("Content-Length: 0");
  AddSipLine("");
  caRead[0] = 0;
  SendUdp();
}

// parse parameter value from http formated string
bool Sip::ParseParameter(char *dest, int destlen, const char *name, const char *line, char cq)
{
  const char *qp;
  const char *r;
  if ((r = strstr(line, name)) != NULL)
  {
    r = r + strlen(name);
    qp = strchr(r, cq);
    int l = qp - r;
    if (l < destlen)
    {
      strncpy(dest, r, l);
      dest[l] = 0;
      return true;
    }
  }
  return false;
}

// search a line in response date (p) and append on
// pbuf
bool Sip::AddCopySipLine(const char *p, const char *psearch)
{
  char *pa = strstr((char*)p, psearch);
  if (pa)
  {
    char *pe = strstr(pa, "\r");
    if (pe == 0)
      pe = strstr(pa, "\n");
    if (pe > pa)
    {
      char c = *pe;
      *pe = 0;
      AddSipLine("%s", pa);
      *pe = c;
      return true;
    }
  }
  return false;
}

int Sip::GrepInteger(const char *p, const char *psearch)
{
  int param = -1;
  const char *pc = strstr(p, psearch);
  if (pc)
  {
    param = atoi(pc + strlen(psearch));
  }
  return param;
}

// copy Call-ID, From, Via and To from response
// to caRead
// using later for BYE or CANCEL the call
bool Sip::ParseReturnParams(const char *p)
{
  pbuf[0] = 0;
  AddCopySipLine(p, "Call-ID: ");
  AddCopySipLine(p, "From: ");
  AddCopySipLine(p, "Via: ");
  AddCopySipLine(p, "To: ");
  if (strlen(pbuf) >= 2)
  {
    strcpy(caRead, pbuf);
    caRead[strlen(caRead) - 2] = 0;
  }
  return true;
}

void Sip::HandleUdpPacket(const char *p)
{
  uint32_t iWorkTime = iRingTime ? (Millis() - iRingTime) : 0;
  if (iRingTime && iWorkTime > iMaxTime)
  {
    // Cancel(3);
    Bye(3);
    iRingTime = 0;
  }

  if (!p)
  {
    // max 5 dial retry when loos first invite packet
    if (iAuthCnt == 0 && iDialRetries < 5 && iWorkTime > (iDialRetries * 200))
    {
      iDialRetries++;
      delay(30);
      Invite();
    }
    return;
  }

  if (strstr(p, "SIP/2.0 401 Unauthorized") == p)
  {
    Ack(p);
    // call Invite with response data (p) to build auth md5 hashes
    Invite(p);
  }
  else if (strstr(p, "BYE") == p)
  {
    Ok(p);
    iRingTime = 0;
  }
  else if (strstr(p, "SIP/2.0 200") == p)    // OK
  {
    ParseReturnParams(p);
    Ack(p);
  }
  else if (   strstr(p, "SIP/2.0 183 ") == p // Session Progress
              || strstr(p, "SIP/2.0 180 ") == p ) // Ringing
  {
    ParseReturnParams(p);
  }
  else if (strstr(p, "SIP/2.0 100 ") == p)   // Trying
  {
    ParseReturnParams(p);
    Ack(p);
  }
  else if (   strstr(p, "SIP/2.0 486 ") == p // Busy Here
              || strstr(p, "SIP/2.0 603 ") == p // Decline
              || strstr(p, "SIP/2.0 487 ") == p) // Request Terminatet
  {
    Ack(p);
    iRingTime = 0;
  }
  else if (strstr(p, "INFO") == p)
  {
    iLastCSeq = GrepInteger(p, "\nCSeq: ");
    Ok(p);
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// hardware dependent interface functions
//
/////////////////////////////////////////////////////////////////////////////////////////////////////

int Sip::SendUdp()
{
  Udp.beginPacket(pSipIp, iSipPort);
  Udp.write(pbuf, strlen(pbuf));
  Udp.endPacket();
  return 0;
}

// generate a 30 bit random number
uint32_t Sip::Random()
{
  // return ((((uint32_t)rand())&0x7fff)<<15) + ((((uint32_t)rand())&0x7fff));
  return secureRandom(0x3fffffff);
}

uint32_t Sip::Millis()
{
  return (uint32_t)millis() + 1;
}

void Sip::MakeMd5Digest(char *pOutHex33, char *pIn)
{
  MD5Builder aMd5;
  aMd5.begin();
  aMd5.add(pIn);
  aMd5.calculate();
  aMd5.getChars(pOutHex33);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Arduino setup() and loop()
//
/////////////////////////////////////////////////////////////////////////////////////////////////////

char caSipIn[2048];
char caSipOut[2048];
Sip aSip(caSipOut, sizeof(caSipOut));

void setup()
{
  WiFi.softAPdisconnect (true);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);

  IPAddress Ip;
  IPAddress Gw;
  IPAddress Mask;
  IPAddress Dns;

  Ip.fromString(ip);
  Gw.fromString(gw);
  Mask.fromString(mask);
  Dns.fromString(dns);

  WiFi.config(Ip, Gw, Mask, Dns);

  if (String(ssid) != WiFi.SSID())
  {
    WiFi.begin(ssid, password);
  }
  // Verbindung zum router Herstellen
  int i = 0;
  for (i = 0; i < 100; i++)
  {
    if (WiFi.status() == WL_CONNECTED)
      break;
    delay(100);
  }

  if (i >= 100)
  {
    // without connection go to sleep
    delay(1000);
  }

  WiFi.persistent(true);
  Udp.begin(sipport);
  aSip.Init(sipip, sipport, ip, sipport, sipuser, sippasswd, 15);
  //aSip.Dial(sipdialnr, sipdialtext);
}
int deepSleepDelay = 0;

void loop(void)
{
  int packetSize = Udp.parsePacket();
  if (packetSize > 0)
  {
    caSipIn[0] = 0;
    packetSize = Udp.read(caSipIn, sizeof(caSipIn));
    if (packetSize > 0)
    {
      caSipIn[packetSize] = 0;
    }
  }
  aSip.HandleUdpPacket((packetSize > 0) ? caSipIn : 0 );
  if (!aSip.IsBusy() && deepSleepDelay == 0)
    deepSleepDelay = millis();
  if (deepSleepDelay && (millis() - deepSleepDelay) > 500)
  {}

  // Ab Hier ist euer Programm


  // GPIO 13 auf minus gezogen wird
  if (digitalRead(13) == LOW) {
    //aSip.Dial("**9", "GPIO D7 !");
    aSip.Dial("**701", "Klingel Tuer");
  }

  if (digitalRead(12) == LOW) {
    //aSip.Dial("**9", "GPIO D6 !");
    aSip.Dial("**610", "Klingel Tor");
  }



}

Danke dir erstmal :)

: Bearbeitet durch User
von Alois N. (alois)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

im loop wird die Abfrage des Digitalen Eingang ständig abgefragt und bei 
einem Tastendruck die Routine aSip.Dial("**610", "Klingel Tor"); gleich 
mehrmals aufgerufen (solange der Taster gedrückt wird). Ich vermute das 
der Stack überläuft und das Programm abstürzt und dann das von Dir 
beschriebene Phänomen zeigt.

Welches ESP Modul hast Du den? Kannst Du ein Link oder ein Bild posten.

Ich passe den Source Code für Dich an.
Siehe: Beitrag "Re: Sipdial per ESP8266 an Fritzbox"

Gruß Alois

: Bearbeitet durch User
von Michael R. (michael_r233)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi Alois,

vielen Dank dafür schonmal im vorraus. Was ich nicht verstehe ist, das 
niemand anderes dieses Problem hat. ich habe doch im originalcode nichts 
verändert ausser der Rufnummer...

von Nico .. (nico123)


Bewertung
0 lesenswert
nicht lesenswert
Wie weit ist der Weg zwischen Taster und ESP bei dir?

Wie versorgst Du den ESP?

von Michael R. (michael_r233)


Bewertung
0 lesenswert
nicht lesenswert
Alois, Ich habe gerade mal geprüft welches Script ich da habe. es ist 
wohl doch ein irgendwie geändertes Script, nicht ganz das original. 
daher haben wohl nicht viele dasselbe Problem.
Es wäre trotzdem toll wenn du den Fehler ausbügeln könntest :)


Nico, Vom Klingeltaster zum ESP sind es etwa 8m. USB Netzteil bzw. auch 
Batteriepack.

: Bearbeitet durch User
von Nico .. (nico123)


Bewertung
0 lesenswert
nicht lesenswert
Bei 8m Klingeldraht ist es kein Wunder, dass Du Störungen hast!
Oder hast Du geschirmtes Kabel benutzt?

von Michael R. (michael_r233)


Bewertung
0 lesenswert
nicht lesenswert
Cat6 Kabel.

von Nico .. (nico123)


Bewertung
0 lesenswert
nicht lesenswert
Schirm angeschlossen?
Und ein verdrilltes Adernpaar benutzt?

: Bearbeitet durch User
von erdna1281 (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo ich möchte mich auch bei euch bedanken, ich konnte nun meinen 
unzuverlässigen RPI1 in den verdienten Ruhestand schicken. Weiterer 
Vorteil, die Telefone klingen quasi instant mit, statt erst mit 
sekundenlanger Verzögerung.

von Alois N. (alois)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

ich habe den Source-Code überarbeitet und etwas übersichtlicher 
gestaltet.

NodemMCU V3:
Klingeltaster 1 = GPIO12 (D6)
Klingeltaster 2 = GPIO13 (D7)
Türöffner = GPIO14 (D5)

Wenn ein Klingeltaster gedrückt wird, geht die BUILTIN-LED solange an 
das Klingeln aktiv ist.

Durch Abheben des Telefonhörers und betätigen der Ziffer "5" am Telefon 
wird der Türöffner für 2 Sekunden ausgelöst.

Gruß Alois.

von Alois N. (alois)


Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Hallo Michael,

und hier ein Bilder von meinem Siedle Haustelefon HT-511 mit eingebauter 
selbstentwickelter Platine (Format 37.9 x 36.1 mm).

ESP-01:
Klingeltaster 1 = GPIO02
Klingeltaster 2 = GPIO00
Türöffner       = GPIO01


Die Klingeltaster Eingänge sowie der Türöffner Ausgang sind LOW
schaltend. Das hat den Hintergrund das die Pins des ESP-01 Moduls
nachdem Anlegen der Versorgungsspannung alle erst HIGH aktiv sind.

Ich hatte die Schaltung zuvor mit einem NPN Transistor für die 
Relaisansteuerung aufgebaut. Das hatte aber den Effekt das der
Türöffner beim Anlegen der Versorgungsspannung kurzzeitig
angesteuert wurde.

Auf der Platine befindet sich auch ein 3,3V Step-Down-Abwärtswandler
und eine Gleichrichtung. Die Schaltung lässt sich somit mit Gleich-
und Wechselspannung versorgen.

Gruß Alois.

: Bearbeitet durch User
von Ralf A. (lonestar62)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Alois,

hast du noch eine von den Platinen die du weitergeben kannst.
Natürlich nicht kostenlos.

Danke und Grüße

Ralf

von Castle R. (castle)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Alois,

hier noch ein Hinweis, wenn man die ganz alten ESP01 verwendet.
Der wollte mit deiner Schaltung erstmal nicht funktionieren. Hier musste 
der Pin CH_PD mit einem PullUp von 10kOhm auf 3,3V gelegt werden.
Jetzt funktioniert es.
Vielen Dank für deine Schaltung. :)

von Jürgen L. (jliegner)


Bewertung
0 lesenswert
nicht lesenswert
Alois N. schrieb:
> Hallo Michael,
>
> ich habe den Source-Code überarbeitet und etwas übersichtlicher
> gestaltet.

Ich habe zwar keine Einschränkungen bei der Verwendung meines Codes 
gemacht, finde es aber trotzdem relativ anmassend, wenn du in der sip.h 
bzw. sip.cpp angibts der Author des Codes zu sein.

von Alois N. (alois)


Bewertung
0 lesenswert
nicht lesenswert
Jürgen L. schrieb:
> Ich habe zwar keine Einschränkungen bei der Verwendung meines Codes
> gemacht, finde es aber trotzdem relativ anmassend, wenn du in der sip.h
> bzw. sip.cpp angibts der Author des Codes zu sein.
Hallo Jürgen,

Sorry, aber das war ein versehen. Ich habe sofort eine Löschanforderung 
für den Beitrag gestellt. Eigentlich war das nur mein privater Code den 
ich für meine kleine Siedele Türklingel und -öffner Schaltung auf meinem 
Rechner hatte. Bei der Anfrage von dem Benutzer Michael habe ich den 
Source ohne Verweis auf den eigentlichen Autor hier veröffentlicht. Ich 
kann mich nur bei Dir dafür entschuldigen.

Ich wünsche trotz allem einen schönen Sonntag
Alois

von Alois N. (alois)


Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Hallo Jürgen,

Die Mods haben den Anhang aus dem ursprünglichen Beitrag gelöscht und 
mich gebeten den Source Code erneut mit entsprechender Quellenangabe 
hochzuladen.
Ist das so ok für dich?

Gruß Alois

von Jürgen L. (jliegner)


Bewertung
1 lesenswert
nicht lesenswert
Danke für die schnelle Reaktion und Berichtigung.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.