Micropython auf GSM + GPS-Modul A9G

Dieses Mal habe ich vorsichtshalber darüber nachgedacht, einen GPS-Tracker in meinem Fahrrad zu verstecken. Auf dem Markt gibt es unzählige autonome Geräte zur Verfolgung von Autos, Fracht, Fahrrädern, Gepäck, Kindern und Tieren. Die überwiegende Mehrheit von ihnen interagiert mit dem Benutzer per SMS. Teurere Optionen bieten die Funktion "Mein Telefon suchen", sind jedoch an einen bestimmten Onlinedienst gebunden.
Idealerweise möchte ich die volle Kontrolle über den Tracker haben: Verwenden Sie ihn in einem praktischen Modus ohne SMS und Registrierung. Oberflächliches Google brachte mir ein paar Module aus China, von denen ich eines bestellte (A9G Pudding Board) (~ 15 $).


Modul


In diesem Artikel geht es darum, wie Python in diesem Modul funktioniert.


Wenn der A9G ein Analogon von ESP ist (der Hersteller ist übrigens derselbe), ist die Puddingplatine selbst ein Analogon der NodeMCU-Platine, außer dass die Puddingplatine keinen eingebauten USB-UART-Konverter hat. Aber es gibt noch viele andere interessante Dinge. Herstellerspezifikationen :


  • 32-Bit-Kern (RISC), bis zu 312 MHz
  • 29x GPIO (alle sind verlötet, alle Schnittstellen sind in dieser Nummer enthalten)
  • Uhren und Wachhund
  • 1x USB 1.1-Schnittstelle (ich habe sie dort nicht gefunden, aber von außerhalb kopiert) und microUSB für die Stromversorgung
  • 2x UART (+1 Service)
  • 2x SPI (nicht ausprobiert)
  • 3x I2C (nicht ausprobiert)
  • 1x SDMMC (mit physischem Steckplatz)
  • 2x analoge Eingänge (10 Bit, möglicherweise einer davon wird von Lithium-Batterie-Controllern verwendet)
  • 4 MB Flash
  • 4 MB PSRAM
  • ADC (Mikrofon, physisch vorhanden auf der Platine) und DAC (Lautsprecher, nicht vorhanden)
  • Batterieladesteuerung (es gibt keine Batterie selbst)
  • in der Tat GSM (800, 900, 1800, 1900 MHz) mit SMS, Sprache und GPRS
  • GPS über UART2 verbunden (es gibt ein "A9" -Modul ohne es)
  • SIM-Steckplatz (nanoSIM)
  • zwei Tasten (eine zurückgesetzt, die andere - Aufnahme und programmierbare Funktion)
  • zwei LEDs

Die Betriebsspannung beträgt 3,3 V, die Eingangsspannung 5-3,8 V (je nach Anschluss). Im Allgemeinen verfügt das Modul über die erforderliche Hardware, um daraus ein einfaches mobiles Druckknopfgerät zusammenzusetzen. Aber aus den Beispielen geht hervor, dass die Chinesen es zum Verkauf an Spielautomaten oder Spielautomaten oder ähnlichem kaufen. Alternativen zum Modul sind die recht beliebten SIM800-Module, die leider kein öffentlich zugängliches SDK haben (d. H. Die Module werden als AT-Modems verkauft).


SDK


Das Modul wird mit einem SDK in zufriedenstellendem Englisch geliefert. Wird unter Ubuntu installiert, Windows und Container werden jedoch bevorzugt. Alles funktioniert durch Stöbern in der GUI: ESPtool für dieses Modul muss noch zurückgesetzt werden. Die Firmware selbst wird vom Makefile erstellt. Der Debugger ist vorhanden: Vor dem Einfrieren wirft das Modul den Stack-Trace in den Service-Port. Aber persönlich konnte ich die Adressen nicht in Codezeilen übersetzen (GDB berichtet, dass die Adressen nichts entsprechen). Möglicherweise liegt dies an der schlechten Unterstützung von Linux als solchem. Wenn Sie also mit dem Modul basteln möchten, versuchen Sie es unter Windows (und melden Sie sich bei github ab). Ansonsten ist hier die Anleitung für Linux. Nach der Installation müssen Sie die Richtigkeit der Pfade in .bashrc überprüfen und alle CSDTK/lib/libQt* löschen (umbenennen). CSDTK/lib/libQt* der CSDTK/lib/libQt* (auch als Debugger bezeichnet) aufgrund eines Konflikts mit wahrscheinlich installiertem libQt einfach nicht gestartet.


Blinker


Zum Blinker gibt es eine Anweisung .


Verbindung


Alles ist komplizierter als bei NodeMCU. Die Module sehen ähnlich aus, aber es gibt keinen USB-TTY-Chip auf der Puddingplatte und microUSB wird nur für die Stromversorgung verwendet. Dementsprechend benötigen Sie USB-TTY bei 3,3V. Zwei sind besser: einer für den Debug-Port und einer für UART1: Der erste dient zum Hochladen der Firmware und der zweite kann als reguläres Terminal verwendet werden. Um nicht all diesen Rotz auf den Computer zu ziehen, habe ich zusätzlich einen 4-Port-USB-Splitter mit einem zwei Meter langen Kabel und einem externen Netzteil (erforderlich) gekauft. Die Gesamtkosten für dieses Kit mit dem Modul selbst betragen 25 bis 30 USD (ohne Stromversorgung: Verwendung über das Telefon).


Firmware


Das Modul wird mit AT-Firmware geliefert: Sie können eine Verbindung zu einem 3,3-V-Arduino herstellen und es über UART1 als Modem verwenden. Ihre Firmware ist in C geschrieben. make erstellt zwei Firmware-Dateien: Eine wird etwa eine Minute lang genäht, die andere ist schnell genug. Es kann nur eine dieser Dateien genäht werden: Das erste Mal ist groß, die folgenden Zeiten sind klein. Insgesamt habe ich während des Entwicklungsprozesses das chinesische SDK ( coolwatcher ) auf dem Desktop geöffnet, um das Modul zu verwalten, miniterm als stdio und den Code-Editor.


API


Der Inhalt der API spiegelt die obige Liste wider und ähnelt dem ESP8266 in seinen Anfängen: Ich habe ungefähr 3 Stunden gebraucht, um HelloWorld zu starten. Leider sind die Funktionen, die dem Benutzer zur Verfügung stehen, sehr begrenzt: Beispielsweise gibt es keinen Zugriff auf das Telefonbuch auf der SIM-Karte, Informationen auf niedriger Ebene zum Herstellen einer Verbindung zum Mobilfunknetz usw. Die API-Dokumentation ist noch weniger vollständig, daher müssen Sie sich auf Beispiele (von denen es zwei Dutzend gibt) verlassen und Dateien einschließen. Trotzdem kann das Modul viele Dinge bis hin zu SSL-Verbindungen tun: Offensichtlich hat sich der Hersteller auf die Funktionen mit der höchsten Priorität konzentriert.


Die Programmierung chinesischer Mikrocontroller über die chinesische API muss jedoch geliebt werden. Für alle anderen begann der Hersteller , Micropython auf dieses Modul zu portieren . Ich habe mich entschlossen, mich in einem Open-Source-Projekt zu versuchen und diese gute Arbeit fortzusetzen (Link am Ende des Artikels).


Mikropython


Logo


Micropython ist ein Open-Source-Projekt, das cPython auf Mikrocontroller portiert. Die Entwicklung erfolgt in zwei Richtungen. Die erste ist die Unterstützung und Entwicklung von Kernbibliotheken, die allen Mikrocontrollern gemeinsam sind und die Arbeit mit den wichtigsten Datentypen in Python beschreiben: Objekte, Funktionen, Klassen, Zeichenfolgen, Atomtypen und mehr. Das zweite sind in der Tat die Ports: Für jeden Mikrocontroller muss die Bibliothek „gelehrt“ werden, mit UART für die Eingabe / Ausgabe zu arbeiten, einen Stapel für eine virtuelle Maschine auswählen und eine Reihe von Optimierungen angeben. Optional wird die Arbeit mit Hardware beschrieben: GPIO, Stromversorgung, WLAN, Dateisystem.
All dies ist in reinem C mit Makros geschrieben: micropython bietet eine Reihe empfohlener Rezepte, von der Deklaration von Zeichenfolgen im ROM bis zum Schreiben von Modulen. Darüber hinaus werden selbst geschriebene Python-Module vollständig unterstützt (die Hauptsache ist, die Speichergröße nicht zu vergessen). Die Kuratoren des Projekts hatten sich zum Ziel gesetzt , einen Dzhanga (Bild mit einem Laib Brot) zu lancieren . Als Werbung: Das Projekt verkauft ein eigenes Board für Pyboard- Studenten, aber auch Ports für die Module ESP8266 und ESP32 sind beliebt.


Wenn die Firmware fertig ist und hochgeladen wurde, stellen Sie einfach über UART eine Verbindung zum Mikrocontroller her und gelangen in die Python-REPL.


 $ miniterm.py /dev/ttyUSB1 115200 --raw MicroPython cd2f742 on 2017-11-29; unicorn with Cortex-M3 Type "help()" for more information. >>> print("hello") hello 

Danach können Sie mit dem Schreiben in fast normalem Python3 beginnen, ohne die Speicherbeschränkungen zu vergessen.


Ein A9G-Modul wird nicht offiziell unterstützt (eine Liste der offiziell unterstützten Module ist in micropython/ports verfügbar, es gibt ungefähr ein Dutzend davon). Trotzdem gabelte der Eisenhersteller Micropython und schuf die Umgebung für den A9G-Port: micropython/ports/gprs_a9 , wofür er sich sehr bedankt. Als ich mich für dieses Problem interessierte, wurde der Port erfolgreich kompiliert und der Mikrocontroller begrüßte mich mit REPL. Leider wurde von Modulen von Drittanbietern nur mit dem Dateisystem und GPIO gearbeitet: Es war nichts in Bezug auf das drahtlose Netzwerk und GPS verfügbar. Ich habe mich entschlossen, diesen Fehler zu beheben und mir das Ziel gesetzt, alle für einen GPS-Tracker erforderlichen Funktionen zu portieren. Die offizielle Dokumentation für diesen Fall ist unnötig kurz: Deshalb musste ich mich im Code umsehen.


Wo soll ich anfangen?


Gehen Sie zunächst zu micropython/ports und kopieren Sie micropython/ports/minimal in den neuen Ordner, in dem sich der Port befindet. Bearbeiten Sie dann main.c für Ihre Plattform. Denken Sie daran, dass sich alle Leckereien in der Hauptfunktion befinden, in der Sie den Initialisierer mp_init() aufrufen mp_init() , nachdem Sie zuvor die Einstellungen für den Mikrocontroller und den Stapel vorbereitet haben. Anschließend müssen Sie für die ereignisgesteuerte API pyexec_event_repl_init() aufrufen und die über UART eingegebenen Zeichen der Funktion pyexec_event_repl_process_char(char) . Dies bietet Interoperabilität durch REPL. Die zweite Datei, micropython/ports/minimal/uart_core.c beschreibt das Blockieren der Ein- und Ausgabe in UART. Ich bringe den Originalcode für STM32 für diejenigen mit, die zu faul sind, um danach zu suchen.


main.c


 int main(int argc, char **argv) { int stack_dummy; stack_top = (char*)&stack_dummy; #if MICROPY_ENABLE_GC gc_init(heap, heap + sizeof(heap)); #endif mp_init(); #if MICROPY_ENABLE_COMPILER #if MICROPY_REPL_EVENT_DRIVEN pyexec_event_repl_init(); for (;;) { int c = mp_hal_stdin_rx_chr(); if (pyexec_event_repl_process_char(c)) { break; } } #else pyexec_friendly_repl(); #endif //do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT); //do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT); #else pyexec_frozen_module("frozentest.py"); #endif mp_deinit(); return 0; } 

uart_core.c


 // Receive single character int mp_hal_stdin_rx_chr(void) { unsigned char c = 0; #if MICROPY_MIN_USE_STDOUT int r = read(0, &c, 1); (void)r; #elif MICROPY_MIN_USE_STM32_MCU // wait for RXNE while ((USART1->SR & (1 << 5)) == 0) { } c = USART1->DR; #endif return c; } // Send string of given length void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { #if MICROPY_MIN_USE_STDOUT int r = write(1, str, len); (void)r; #elif MICROPY_MIN_USE_STM32_MCU while (len--) { // wait for TXE while ((USART1->SR & (1 << 7)) == 0) { } USART1->DR = *str++; } #endif } 

Danach müssen Sie das Makefile mit den Empfehlungen / dem Compiler des Herstellers neu schreiben: Hier ist alles individuell. Alles, dies sollte im Idealfall ausreichen: Wir sammeln, füllen die Firmware aus und sehen REPL in UART.
Nachdem Sie micropython wiederbelebt micropython Sie sich um sein Wohlbefinden kümmern: micropython Sie den Garbage Collector ein, die richtige Reaktion auf Strg-D (Soft Reset) und einige andere Dinge, auf die ich nicht mpconfigport.h werde: siehe die Datei mpconfigport.h .


Erstellen Sie ein Modul


Am interessantesten ist es, eigene Module zu schreiben. Das Modul (nicht notwendig, aber wünschenswert) beginnt also mit einer eigenen mod[].c Datei, die vom Makefile hinzugefügt wird ( SRC_C Variable, wenn Sie der Konvention folgen). Ein leeres Modul lautet wie folgt:


 // nlr - non-local return:  C  ,      goto-  . //  nlr_raise             . #include "py/nlr.h" //   .  ,  mp_map_elem_t,  ,   . #include "py/obj.h" //   . mp_raise_ValueError(char* msg)  mp_raise_OSError(int errorcode)   . //  ,   mp_call_function_*     Callable (  callback-). #include "py/runtime.h" #include "py/binary.h" //  header   :       #include "portmodules.h" //    --  .     MP_QSTR_[ ]. MP_OBJ_NEW_QSTR   . //             RAM. //      -      __name__ STATIC const mp_map_elem_t mymodule_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_mymodule) }, }; //      STATIC MP_DEFINE_CONST_DICT (mp_module_mymodule_globals, mymodule_globals_table); //   :             const mp_obj_module_t mp_module_mymodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_mymodule_globals, }; 

Natürlich erkennt der Port selbst die Konstante mp_module_mymodule : Sie muss der Variablen MICROPY_PORT_BUILTIN_MODULES in den mpconfigport.h MICROPY_PORT_BUILTIN_MODULES mpconfigport.h . Übrigens langweilige Tapeten Dort ändern sich auch der Chipname und der Portname. Nach all diesen Änderungen können Sie versuchen, das Modul zu kompilieren und aus REPL zu importieren. Für das Modul ist nur ein __name__ Attribut mit dem __name__ verfügbar (ein __name__ Fall für die Überprüfung der automatischen Vervollständigung in REPL über die Registerkarte).


 >>> import mymodule >>> mymodule.__name__ 'mymodule' 

Konstanten


Die nächste Stufe der Komplexität ist das Hinzufügen von Konstanten. Für Einstellungen ( INPUT , OUTPUT , HIGH , LOW usw.) sind häufig Konstanten erforderlich. OUTPUT ist alles recht einfach. Hier ist zum Beispiel die Konstante magic_number = 10 :


 STATIC const mp_map_elem_t mymodule_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_mymodule) }, { MP_OBJ_NEW_QSTR(MP_QSTR_magic_number), MP_OBJ_NEW_SMALL_INT(10) }, }; 

Testen:


 >>> import mymodule >>> mymodule.magic_number 10 

Funktionen


Das Hinzufügen einer Funktion zu einem Modul folgt dem allgemeinen Prinzip: deklarieren, umbrechen, hinzufügen (ich gebe ein etwas komplexeres Beispiel als in der Dokumentation).


 //  STATIC mp_obj_t conditional_add_one(mp_obj_t value) { //   int.         -  :   . int value_int = mp_obj_get_int(value); value_int ++; if (value_int == 10) { //  None return mp_const_none; } //   int return mp_obj_new_int(value); } //    .     // runtime.h   . STATIC MP_DEFINE_CONST_FUN_OBJ_1(conditional_add_one_obj, conditional_add_one); //  STATIC const mp_map_elem_t mymodule_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_mymodule) }, { MP_OBJ_NEW_QSTR(MP_QSTR_magic_number), MP_OBJ_NEW_SMALL_INT(10) }, { MP_OBJ_NEW_QSTR(MP_QSTR_conditional_add_one), (mp_obj_t)&conditional_add_one_obj }, }; 

Test:


 >>> import mymodule >>> mymodule.conditional_add_one(3) 4 >>> mymodule.conditional_add_one(9) >>> 

Klassen (Typen)


Bei Klassen (Typen) ist auch alles relativ einfach. Hier ist ein Beispiel aus der Dokumentation (na ja, fast):


 //     STATIC const mp_map_elem_t mymodule_hello_locals_dict_table[] = {}; //   STATIC MP_DEFINE_CONST_DICT(mymodule_hello_locals_dict, mymodule_hello_locals_dict_table); // ,  ,   const mp_obj_type_t mymodule_helloObj_type = { //    { &mp_type_type }, // : helloObj .name = MP_QSTR_helloObj, //  .locals_dict = (mp_obj_dict_t*)&mymodule_hello_locals_dict, }; //    STATIC const mp_map_elem_t mymodule_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_mymodule) }, { MP_OBJ_NEW_QSTR(MP_QSTR_magic_number), MP_OBJ_NEW_SMALL_INT(10) }, { MP_OBJ_NEW_QSTR(MP_QSTR_conditional_add_one), (mp_obj_t)&conditional_add_one_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_conditional_add_one), (mp_obj_t)&mymodule_helloObj_type }, }; 

Test:


 >>> mymodule.helloObj <type 'helloObj'> 

Der resultierende Typ kann vererbt und verglichen werden, hat jedoch keinen Konstruktor oder zugehörige Daten. Die Daten werden "neben" dem Konstruktor hinzugefügt: Es wird vorgeschlagen, eine separate Struktur zu erstellen, in der der Python-Typ separat und separat gespeichert wird - ein beliebiger Datensatz.


 //  -. ,    typedef struct _mymodule_hello_obj_t { //   mp_obj_base_t base; // -  uint8_t hello_number; } mymodule_hello_obj_t; 

Wie interagiere ich mit diesen Daten? Eine der schwierigsten Möglichkeiten ist der Konstruktor.


 // -,   (,  ,   mymodule_helloObj_type //   ,     - ),   (args  kwargs)  //        : args, kwargs STATIC mp_obj_t mymodule_hello_make_new( const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args ) { //    mp_arg_check_num(n_args, n_kw, 1, 1, true); //   mymodule_hello_obj_t *self = m_new_obj(mymodule_hello_obj_t); //     self->base.type = &mymodule_hello_type; //   self->hello_number = mp_obj_get_int(args[0]) //   return MP_OBJ_FROM_PTR(self); //    __init__, ,  } //      make_new const mp_obj_type_t mymodule_helloObj_type = { { &mp_type_type }, .name = MP_QSTR_helloObj, .locals_dict = (mp_obj_dict_t*)&mymodule_hello_locals_dict, //  .make_new = mymodule_hello_make_new, }; 

Von den anderen Feldern gibt es auch .print , und ich denke, der Rest der Magie von Python3 .


make_new ist jedoch überhaupt nicht erforderlich, um eine Instanz eines Objekts make_new : Die Initialisierung kann in einer beliebigen Funktion erfolgen. Hier ist ein gutes Beispiel aus micropython/ports/esp32/modsocket.c :


 //   :       STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); sock->base.type = &socket_type; sock->domain = AF_INET; sock->type = SOCK_STREAM; sock->proto = 0; sock->peer_closed = false; if (n_args > 0) { sock->domain = mp_obj_get_int(args[0]); if (n_args > 1) { sock->type = mp_obj_get_int(args[1]); if (n_args > 2) { sock->proto = mp_obj_get_int(args[2]); } } } sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); if (sock->fd < 0) { exception_from_errno(errno); } _socket_settimeout(sock, UINT64_MAX); return MP_OBJ_FROM_PTR(sock); } //     0-3  STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket); 

Gebundene Methoden


Der nächste Schritt ist das Hinzufügen der gebundenen Methoden. Dies unterscheidet sich jedoch nicht wesentlich von allen anderen Methoden. Wir kehren aus der Dokumentation zum Beispiel zurück:


 //    :     1 (self) STATIC mp_obj_t mymodule_hello_increment(mp_obj_t self_in) { mymodule_hello_obj_t *self = MP_OBJ_TO_PTR(self_in); self->hello_number += 1; return mp_const_none; } //     MP_DEFINE_CONST_FUN_OBJ_1(mymodule_hello_increment_obj, mymodule_hello_increment); //      'inc' STATIC const mp_map_elem_t mymodule_hello_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_inc), (mp_obj_t)&mymodule_hello_increment_obj }, } 

Das ist alles!


 >>> x = mymodule.helloObj(12) >>> x.inc() 

Alle anderen Attribute: getattr , setattr


Wie wäre es mit dem Hinzufügen von @property mit @property und im Allgemeinen Ihrem eigenen __getattr__ ? Bitte: Dies erfolgt manuell unter Umgehung von mymodule_hello_locals_dict_table .


 //     ... STATIC void mymodule_hello_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mymodule_hello_obj_t *self = MP_OBJ_TO_PTR(self_in); if (dest[0] != MP_OBJ_NULL) { // __setattr__ if (attr == MP_QSTR_val) { self->val = dest[1]; dest[0] = MP_OBJ_NULL; } } else { // __getattr__ if (attr == MP_QSTR_val) { dest[0] = self->val; } } } // ...     attr const mp_obj_type_t mymodule_helloObj_type = { { &mp_type_type }, .name = MP_QSTR_helloObj, //     //.locals_dict = (mp_obj_dict_t*)&mymodule_hello_locals_dict, .make_new = mymodule_hello_make_new, //   - attr .attr = mymodule_hello_attr, }; 

Es hat sich etwas schmerzhaft Prägnantes herausgestellt, sagen Sie. Wo sind all diese mp_raise_AttributeError ( Hinweis : Eine solche Funktion gibt es nicht)? Tatsächlich wird ein AttributeError automatisch aufgerufen. Das Geheimnis ist, dass dest ein Array von zwei Elementen ist. Das erste Element hat die Bedeutung "Ausgabe", schreibgeschützt: Es nimmt den Wert MP_OBJ_SENTINEL wenn der Wert geschrieben werden muss, und MP_OBJ_NULL wenn er gelesen werden muss. Dementsprechend wird beim Verlassen der Funktion im ersten Fall mp_obj_t im zweiten etwas mp_obj_t erwartet. Das zweite Element ist schreibgeschützt: MP_OBJ_NULL den Wert des zu schreibenden Objekts, wenn der Wert geschrieben werden muss, und MP_OBJ_NULL wenn er gelesen werden muss. Sie müssen es nicht ändern.


Das ist alles, was Sie überprüfen können:


 >>> x = mymodule.helloObj(12) >>> x.val = 3 >>> x.val 3 

Am interessantesten ist, dass die Tab-Vervollständigung in REPL immer noch funktioniert und .val bietet! Um ehrlich zu sein, bin ich kein Experte für C, daher kann ich nur raten, wie dies geschieht (indem ich den Operator '==' neu definiere).


Hafen


Zurück zum A9G-Modul habe ich die Unterstützung aller Grundfunktionen beschrieben, nämlich SMS, GPRS (Usockets), GPS und Energieverwaltung. Jetzt können Sie so etwas in das Modul hochladen und es wird funktionieren:


 import cellular as c import usocket as sock import time import gps import machine #   print("Waiting network registration ...") while not c.is_network_registered(): time.sleep(1) time.sleep(2) #  GPRS print("Activating ...") c.gprs_activate("internet", "", "") print("Local IP:", sock.get_local_ip()) #  GPS gps.on() #    thingspeak host = "api.thingspeak.com" api_key = "some-api-key" fields = ('latitude', 'longitude', 'battery', 'sat_visible', 'sat_tracked') #  ,      ! fields = dict(zip(fields, map(lambda x: "field{}".format(x+1), range(len(fields))) )) x, y = gps.get_location() level = machine.get_input_voltage()[1] sats_vis, sats_tracked = gps.get_satellites() s = sock.socket() print("Connecting ...") s.connect((host, 80)) print("Sending ...") #      ,     HTTP.           HTTP, SSL   print("Sent:", s.send("GET /update?api_key={}&{latitude}={:f}&{longitude}={:f}&{battery}={:f}&{sat_visible}={:d}&{sat_tracked}={:d} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n".format( api_key, x, y, level, sats_vis, sats_tracked, host, **fields ))) print("Receiving ...") print("Received:", s.recv(128)) s.close() 

Das Projekt freut sich über jede mögliche Hilfe. Wenn Ihnen das Projekt und / oder dieser Artikel gefallen hat, vergessen Sie nicht, ein Like auf dem Github zu hinterlassen .

Source: https://habr.com/ru/post/de446090/


All Articles