simple example of scanning wifi AP and sending to geolocation resolver on cloud

Dependencies:   mbed-http lr1110 sx12xx_hal

test Wifi geolocation with resolving using HTTP POST.

Use with mbed board with internet access and arduino form factor.
With HTTPS, the RAM requirement is minimum 128Kbytes.

and, use with radio shield for europe
or radio shield for USA
which is programmed with trx firmware from updater tool.

This project presents to user mbed STDIO serial port at 115200bps, which lets you perform wifi access point scan on LR1110 and send the resulting access point list to a geolocation provider on the cloud.

Use the project by itself to run wifi scan on the serial terminal (at 115200bps), or use with lr1110_wifi_geolocation_device to receive wifi list from remote device (over LoRa) to resolve location of that device using gelocation provider on cloud.

On serial terminal, use ? question mark to see list of commands. ws to run wifi scan, or ws p to wifi scan and resolve location with cloud provider via HTTP POST.

project setup

Edit main.h to uncomment which geolocation provider you wish to use, and get API key from them:

notice

This project is not using LoRaWAN, instead just LoRa transceiver directly to geolocation provider

Revision:
1:4a05f91c9c38
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combain.cpp	Tue Feb 09 10:49:02 2021 -0800
@@ -0,0 +1,127 @@
+#include "main.h"
+#if (GEOLOCATION_PROVIDER == COMBAIN)
+#include "radio.h"
+
+char my_copy[128];
+
+const char COMBAIN_SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
+"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n"
+"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n"
+"DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n"
+"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n"
+"Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n"
+"AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n"
+"rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n"
+"OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n"
+"xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n"
+"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n"
+"aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n"
+"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n"
+"SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n"
+"ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n"
+"AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n"
+"R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n"
+"JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n"
+"Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n"
+"-----END CERTIFICATE-----\n";
+
+/* parse_json: get result sent from server */
+void parse_json(const char *body, float *lat, float *lng, int *accuracy)
+{
+    bool in_location = false;
+    bool get_lat = false;
+    bool get_lng = false;
+    bool get_accuracy = false;
+    unsigned n;
+    strncpy(my_copy, body, sizeof(my_copy));
+    strtok(my_copy, "\"");
+    for (n = 0; n < 10; n++) {
+        char *t = strtok(NULL, "\":");
+        if (!t)
+            break;
+        if (in_location) {
+            if (get_lat) {
+                sscanf(t, "%f", lat);
+                get_lat = false;
+            } else if (get_lng) {
+                sscanf(t, "%f", lng);
+                get_lng = false;
+            }
+            if (strchr(t, '}'))
+                in_location = false;
+            else if (strcmp(t, "lat") == 0)
+                get_lat = true;
+            else if (strcmp(t, "lng") == 0)
+                get_lng = true;
+        } else {
+            if (get_accuracy) {
+                sscanf(t, "%d", accuracy);
+                get_accuracy = false;
+            }
+            if (strcmp(t, "location") == 0)
+                in_location = true;
+            else if (strcmp(t, "accuracy") == 0)
+                get_accuracy = true;
+        }
+    }
+}
+
+int post_scan_result(const char *body, float *lat, float *lng, int *accuracy)
+{
+    HttpsRequest* post_req = new HttpsRequest(network, COMBAIN_SSL_CA_PEM, HTTP_POST, "https://apiv2.combain.com?key=YOUR_API_KEY");
+
+    post_req->set_header("Content-Type", "application/json");
+
+    HttpResponse* post_res = post_req->send(body, strlen(body));
+    if (!post_res) {
+        printf("HttpRequest failed (error code %d)\n", post_req->get_error());
+        return -1;
+    }
+
+    dump_response(post_res);
+    parse_json(post_res->get_body_as_string().c_str(), lat, lng, accuracy);
+    delete post_req;
+
+    return 0;
+}
+
+/*
+ * https://combain.com/api/#request-body
+ */
+
+void wifi_result_to_json(bool first, const uint8_t *result, unsigned macStart, unsigned rssi_idx)
+{
+    char str[8];
+    unsigned i;
+
+    if (!first)
+        strcat(json, ",");  // end previous wifiAccessPoint
+
+    strcat(json, "{\"macAddress\": \"");
+    for (i = 0; i < 6; i++) {
+        sprintf(str, "%02x", result[i + macStart]);
+        strcat(json, str);
+        if (i < 5)
+            strcat(json, ":");
+    }
+    strcat(json, "\",\"signalStrength\": ");
+    sprintf(str, "%d", (int8_t)result[rssi_idx]);
+    strcat(json, str);
+    /* TODO: combain takes channel and/or frequency of access point */
+
+    strcat(json, "}");
+}
+
+void json_start()
+{
+    strcpy(json, "{\"considerIp\": \"false\",");
+    strcat(json, "\"wifiAccessPoints\": [");
+}
+
+void json_end()
+{
+    strcat(json, "]");
+    strcat(json, "}");
+}
+
+#endif /* GEOLOCATION_PROVIDER == COMBAIN */