Arduino Uno und Siemens TC35: SMS empfangen und Schalter steuern
Im vorhergehenden Teil dieser Reihe wurde erklärt, wie man mit einem Arduino Uno und einem GSM-Board (in diesem Fall mit dem Siemens TC35) SMS versenden kann. Heute nun soll das Programm dahingehend erweitert werden, dass SMS empfangen und ausgewertet werden können und anhand des SMS-Inhalts ein Schalter bzw. ein Pin des Arduino geschaltet werden kann.
Der Schaltungsaufbau ist der gleich, wie er im letzten Versuch verwendet wurde. Hinzugekommen ist ein größeres Stück Software für den Arduino, welches nun die erforderlichen Befehle zum Empfang von SMS an das GSM-Modem sendet.
Die zur Kommunikation verwendete Lib SoftwareSerial definiert nur einen 64 Byte großen Empfangspuffer. Für den Empfang von SMS ist das viel zu wenig. In der Datei hardware/arduino/avr/libraries/SoftwareSerial/SoftwareSerial.h wird die Puffergröße durch _SS_MAX_RX_BUFF festgelegt. Diese Puffergröße sollte dort auf mindestens 1024 festgelegt werden.
#define _SS_MAX_RX_BUFF 1024
Folgende Vorgehensweise im Arduino-Programm für die Initialisierung wurde gewählt:
- Aktivieren der seriellen Schnittstellen zum GSM-Modem wie auch zum Computer (für die Protokollierung und zu Testzwecken)
- Einschalten des GSM-Teils des TC35 über den IGT-Pin
- Löschen aller alten bereits auf der SIM-Karte gespeicherten SMS-Nachrichten
Im anschließenden loop des Arduino wird ermittelt, ob neue SMS-Nachrichten vorliegen. Diese sollen dem Schema "PIN{ ON | OFF | STATUS }" ensprechen. Bei korrekt übermittelter PIN wird bei falschem Kommando eine SMS mit entsprechendem Hilfetext zurückgesendet. ON bewirkt das Einschalten des Schalter, OFF das Ausschalten und STATUS sendet eine SMS mit dem aktuellen Zustand des Schalters an den Sender der SMS zurück.
Arduino-Programm
1#include <SoftwareSerial.h>
2#define rxPin 2
3#define txPin 3
4#define statusPin 13
5#define igtPin 8
6
7String accessPin("1234");
8String cmdOff("OFF");
9String cmdOn("ON");
10String cmdStatus("STATUS");
11
12SoftwareSerial gsmSerial(rxPin, txPin);
13
14String smsNumber;
15String smsText;
16String cmdMessage;
17String cmdResponse;
18
19int nMessages;
20char c;
21int state;
22int switchStatus;
23
24// -------------------------------------------------------------
25void setup()
26{
27 Serial.begin(9600);
28 while(!Serial) {};
29 gsmSerial.begin(9600);
30
31 pinMode(statusPin, OUTPUT);
32 digitalWrite(13, LOW);
33 switchStatus = false;
34
35 // TC35 einschalten, igtPin 100ms auf GND ziehen
36 pinMode(igtPin, INPUT);
37 digitalWrite(igtPin, LOW);
38 pinMode(igtPin, OUTPUT);
39 delay(100);
40 pinMode(igtPin, INPUT);
41 delay(5000);
42
43 // Format Text fuer SMS einstellen
44 SendCmd("AT+CMGF=1");
45
46 CountMessages();
47 DeleteAllMessages();
48
49 Serial.println("Ready");
50}
51
52// -------------------------------------------------------------
53void loop()
54{
55 if (nMessages > 0)
56 {
57 ReadSms(nMessages);
58 Serial.println("Incoming: [" + smsNumber + "] [" + smsText + "]");
59 DeleteMessage(nMessages);
60 nMessages--;
61 if (smsText.length() >= accessPin.length() && smsText.startsWith(accessPin))
62 {
63 smsText.remove(0, accessPin.length());
64 if (smsText == cmdOn)
65 {
66 digitalWrite(13, HIGH);
67 switchStatus = true;
68 }
69 else if (smsText == cmdOff)
70 {
71 digitalWrite(13, LOW);
72 switchStatus = false;
73 }
74 else if (smsText == cmdStatus)
75 {
76 smsText = "Switch is ";
77 if (switchStatus == true)
78 {
79 smsText += cmdOn;
80 }
81 else
82 {
83 smsText += cmdOff;
84 }
85 SendMessage();
86 }
87 else
88 {
89 smsText = "Available commands: " + cmdOn + ", " + cmdOff + " und " + cmdStatus;
90 SendMessage();
91 }
92 }
93 }
94 else
95 {
96 delay(5000);
97 }
98 CountMessages();
99}
100
101// -------------------------------------------------------------
102void SendCmd(String cmd)
103{
104 gsmSerial.println(cmd);
105 delay(1000);
106 while(gsmSerial.available() > 0)
107 {
108 c = gsmSerial.read();
109 }
110 delay(100);
111}
112
113// -------------------------------------------------------------
114void CountMessages()
115{
116 nMessages = 0;
117 cmdMessage = "AT+CPMS=\"SM\"";
118 gsmSerial.println(cmdMessage);
119 delay(1000);
120
121 cmdResponse = "";
122 state = 0;
123
124 String num = "";
125 while(gsmSerial.available() > 0)
126 {
127 c = gsmSerial.read();
128 if (c != 13 && c != 10)
129 {
130 cmdResponse += c;
131 }
132
133 if (c == ':' && state == 0)
134 {
135 // Leerzeichen vor der ersten Zahl
136 c = gsmSerial.read();
137 state = 1;
138 }
139 if (c != ' ' && state == 1)
140 {
141 // Anfang der ersten Zahl
142 state = 2;
143 }
144 if (c == ',' && state == 2)
145 {
146 // Ende der ersten Zahl
147 state = 3;
148 }
149 if (state == 2)
150 {
151 num += c;
152 }
153 }
154 nMessages = num.toInt();
155}
156
157// -------------------------------------------------------------
158void DeleteAllMessages()
159{
160 while(nMessages > 0)
161 {
162 DeleteMessage(nMessages);
163 nMessages--;
164 }
165}
166
167// -------------------------------------------------------------
168void DeleteMessage(int smsIndex)
169{
170 cmdMessage = "";
171 cmdMessage = smsIndex + cmdMessage;
172 cmdMessage = "AT+CMGD=" + cmdMessage;
173 SendCmd(cmdMessage);
174}
175
176// -------------------------------------------------------------
177void ReadSms(int smsIndex)
178{
179 cmdMessage = "";
180 cmdMessage = smsIndex + cmdMessage;
181 cmdMessage = "AT+CMGR=" + cmdMessage;
182 gsmSerial.println(cmdMessage);
183 delay(1000);
184
185 smsNumber = "";
186 smsText = "";
187 cmdResponse = "";
188
189 state = 0;
190 // Format: +CMGR: "REC READ","+336xxxxxxxx",,"13/06/10,22:18:35+08"<CR><LF>Message<CR>
191 while(gsmSerial.available() > 0)
192 {
193 c = char(gsmSerial.read());
194 if (c != 13 && c != 10)
195 {
196 cmdResponse += c;
197 }
198
199 if (c == ',' && state == 0)
200 {
201 // Anfang der Telefonnummer
202 c = char(gsmSerial.read()); // " ueberlesen
203 c = char(gsmSerial.read());
204 state = 1;
205 }
206 if (c == '"' && state == 1)
207 {
208 // Ende der Telefonnummer
209 state = 2;
210 }
211 if (c == 13 && state == 2)
212 {
213 // Anfang Text der SMS
214 c = char(gsmSerial.read()); // <LF> ueberlesen
215 state = 3;
216 }
217 if (c == 13 && state == 3)
218 {
219 // Ende Text der SMS
220 state = 4;
221 }
222
223 switch(state)
224 {
225 case 1:
226 smsNumber += c;
227 break;
228 case 3:
229 smsText += c;
230 break;
231 }
232 }
233
234 smsText.toUpperCase();
235 smsText.trim();
236}
237
238// -------------------------------------------------------------
239void SendMessage()
240{
241 if (smsText.length() > 0)
242 {
243 Serial.println("Outgoing: [" + smsText + "] an " + smsNumber);
244
245 cmdMessage = "AT+CMGS=\"" + smsNumber + "\"\r";
246 gsmSerial.print(cmdMessage);
247 delay(1000);
248 gsmSerial.print(smsText);
249 delay(1000);
250 gsmSerial.println((char)26);
251 delay(2000);
252 while(gsmSerial.available() > 0)
253 {
254 c = gsmSerial.read();
255 }
256 }
257}Implementierte Subrouinen:
- SendCmd sendet eine Zeichenkette (einen Befehl) an das GSM-Modem und "verschluckt" die Antwort des Modems
- CountMessages ermittelt mit Hilfe des Befehls AT+CPMS="SM" die aktuelle Anzahl der auf der SIM-Karte gespeicherten SMS (genauer: im Speicherbereich SM)
- DeleteAllMessages löscht, wie der Name schon sagt, alle gespeicherten SMS
- DeleteMessage löscht eine einzelne SMS
- ReadSms ließt eine einzelne SMS aus dem SIM-Speicher aus und speichert die Absender-Telefonnummer in der Variablen smsNumber und den Text in smsText
- SendMessage verschickt eine Nachricht (smsText) an die in smsNumber eingetragene Telefonnummer
Im Kopfteil des Programms kann die PIN festgelegt werden, die zum Übermitteln von Kommandos in der SMS-Nachricht angegeben werden muss.
Im ersten Teil der Reihe wurde beschrieben, wie die Schaltung aufgebaut ist und wie mit dem TC35 SMS versendet werden können. Im dritten Teil der Reihe soll die vorhandene Schaltung um eine Relaiskarte erweitert werden, mit der auch größere Lasten geschaltet werden können.