text: /******************************************************************************
   * Copyright 2019 Google
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *    http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *****************************************************************************/
  // Detect the architecture
  #if defined(ESP8266)
  #define __ESP8266_MQTT_H__
  #endif
  
  #if ESP32
  #define __ESP32_MQTT_H__
  #endif
  
  #if defined(ARDUINO_SAMD_MKR1000)
  #define __MKR1000_MQTT_H__
  #endif
  
  // This file contains static methods for API requests using Wifi / MQTT
  #ifdef __MKR1000_MQTT_H__
  #include <WiFi101.h>
  #include <WiFiSSLClient.h>
  
  #include <MQTT.h>
  
  #include <CloudIoTCore.h>
  #include <CloudIoTCoreMqtt.h>
  #include "ciotc_config.h" // Update this file with your configuration
  
  ///////////////////////////////
  // Cloud IoT configuration that you don't need to change
  Client *netClient;
  CloudIoTCoreDevice *device;
  CloudIoTCoreMqtt *mqtt;
  MQTTClient *mqttClient;
  unsigned long iss = 0;
  String jwt;
  
  ///////////////////////////////
  // Helpers specific to this board
  ///////////////////////////////
  String getDefaultSensor() {
    return  "Wifi: " + String(WiFi.RSSI()) + "db";
  }
  
  String getJwt() {
    // Disable software watchdog as these operations can take a while.
    Serial.println("Refreshing JWT");
    iss = WiFi.getTime();
    jwt = device->createJWT(iss, jwt_exp_secs);
    return jwt;
  }
  
  void setupWifi() {
    Serial.println("Starting wifi");
  
    WiFi.begin(ssid, password);
    Serial.println("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(100);
    }
  
    Serial.println("Waiting on time sync...");
    while (WiFi.getTime() < 1510644967) {
      delay(10);
    }
  }
  
  void connectWifi() {
    Serial.print("checking wifi...");
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print(".");
      delay(1000);
    }
  }
  
  ///////////////////////////////
  // Orchestrates various methods from preceeding code.
  ///////////////////////////////
  void connect() {
    connectWifi();
    mqtt->mqttConnect();
  }
  
  bool publishTelemetry(String data) {
    return return mqtt->publishTelemetry(data);
  }
  
  bool publishTelemetry(String subfolder, String data) {
    return mqtt->publishTelemetry(subfolder, data);
  }
  
  void setupCloudIoT() {
    device = new CloudIoTCoreDevice(
        project_id, location, registry_id, device_id,
        private_key_str);
  
    setupWifi();
    netClient = new WiFiSSLClient();
  
    mqttClient = new MQTTClient(512);
    mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
    mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
    mqtt->startMQTT();
  }
  #endif //__MKR1000_MQTT_H__
  
  
  #ifdef __ESP32_MQTT_H__
  #include <Client.h>
  #include <WiFi.h>
  #include <WiFiClientSecure.h>
  
  #include <MQTT.h>
  
  #include <CloudIoTCore.h>
  #include <CloudIoTCoreMqtt.h>
  #include "ciotc_config.h" // Update this file with your configuration
  
  // Initialize WiFi and MQTT for this board
  Client *netClient;
  CloudIoTCoreDevice *device;
  CloudIoTCoreMqtt *mqtt;
  MQTTClient *mqttClient;
  unsigned long iss = 0;
  String jwt;
  
  ///////////////////////////////
  // Helpers specific to this board
  ///////////////////////////////
  String getDefaultSensor() {
    return  "Wifi: " + String(WiFi.RSSI()) + "db";
  }
  
  String getJwt() {
    iss = time(nullptr);
    Serial.println("Refreshing JWT");
    jwt = device->createJWT(iss, jwt_exp_secs);
    return jwt;
  }
  
  void setupWifi() {
    Serial.println("Starting wifi");
  
    WiFi.mode(WIFI_STA);
    // WiFi.setSleep(false); // May help with disconnect? Seems to have been removed from WiFi
    WiFi.begin(ssid, password);
    Serial.println("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(100);
    }
  
    configTime(0, 0, ntp_primary, ntp_secondary);
    Serial.println("Waiting on time sync...");
    while (time(nullptr) < 1510644967) {
      delay(10);
    }
  }
  
  void connectWifi() {
    Serial.print("checking wifi...");
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print(".");
      delay(1000);
    }
  }
  
  ///////////////////////////////
  // Orchestrates various methods from preceeding code.
  ///////////////////////////////
  bool publishTelemetry(String data) {
    return mqtt->publishTelemetry(data);
  }
  
  bool publishTelemetry(String subfolder, String data) {
    return mqtt->publishTelemetry(subfolder, data);
  }
  
  void connect() {
    connectWifi();
    mqtt->mqttConnect();
  }
  
  void setupCloudIoT() {
    device = new CloudIoTCoreDevice(
        project_id, location, registry_id, device_id,
        private_key_str);
  
    setupWifi();
    netClient = new WiFiClientSecure();
    mqttClient = new MQTTClient(512);
    mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
    mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
    mqtt->startMQTT();
  }
  #endif //__ESP32_MQTT_H__
  
  
  #ifdef __ESP8266_MQTT_H__
  #include <ESP8266WiFi.h>
  #include "FS.h"
  #include <WiFiClientSecure.h>
  #include <time.h>
  
  #include <MQTT.h>
  
  #include <CloudIoTCore.h>
  #include <CloudIoTCoreMqtt.h>
  #include "ciotc_config.h" // Wifi configuration here
  
  ///////////////////////////////
  
  // Initialize WiFi and MQTT for this board
  MQTTClient *mqttClient;
  BearSSL::WiFiClientSecure *netClient;
  BearSSL::X509List certList;
  CloudIoTCoreDevice *device;
  CloudIoTCoreMqtt *mqtt;
  unsigned long iss = 0;
  String jwt;
  
  ///////////////////////////////
  // Helpers specific to this board
  ///////////////////////////////
  String getDefaultSensor() {
    return  "Wifi: " + String(WiFi.RSSI()) + "db";
  }
  
  String getJwt() {
    // Disable software watchdog as these operations can take a while.
    ESP.wdtDisable();
    iss = time(nullptr);
    Serial.println("Refreshing JWT");
    jwt = device->createJWT(iss, jwt_exp_secs);
    ESP.wdtEnable(0);
    return jwt;
  }
  
  void setupCert() {
    // Set CA cert on wifi client
    // If using a static (pem) cert, uncomment in ciotc_config.h:
    certList.append(primary_ca);
    certList.append(backup_ca);
    netClient->setTrustAnchors(&certList);
    return;
  }
  
  void setupWifi() {
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    Serial.println("Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
      delay(100);
    }
  
    configTime(0, 0, ntp_primary, ntp_secondary);
    Serial.println("Waiting on time sync...");
    while (time(nullptr) < 1510644967) {
      delay(10);
    }
  }
  
  void connectWifi() {
    Serial.print("checking wifi..."); // TODO: Necessary?
    while (WiFi.status() != WL_CONNECTED) {
      Serial.print(".");
      delay(1000);
    }
  }
  
  ///////////////////////////////
  // Orchestrates various methods from preceeding code.
  ///////////////////////////////
  bool publishTelemetry(String data) {
    return mqtt->publishTelemetry(data);
  }
  
  bool publishTelemetry(const char* data, int length) {
    return mqtt->publishTelemetry(data, length);
  }
  
  bool publishTelemetry(String subfolder, String data) {
    return mqtt->publishTelemetry(subfolder, data);
  }
  
  bool publishTelemetry(String subfolder, const char* data, int length) {
    return mqtt->publishTelemetry(subfolder, data, length);
  }
  
  void connect() {
    mqtt->mqttConnect();
  }
  
  // TODO: fix globals
  void setupCloudIoT() {
    // Create the device
    device = new CloudIoTCoreDevice(
        project_id, location, registry_id, device_id,
        private_key_str);
  
    // ESP8266 WiFi setup
    netClient = new WiFiClientSecure();
    setupWifi();
  
    // ESP8266 WiFi secure initialization
    setupCert();
  
    mqttClient = new MQTTClient(512);
    mqttClient->setOptions(180, true, 1000); // keepAlive, cleanSession, timeout
    mqtt = new CloudIoTCoreMqtt(mqttClient, netClient, device);
    mqtt->setUseLts(true); // Long-term service for MQTT
    mqtt->startMQTT(); // Opens connection
  }
  #endif //__ESP8266_MQTT_H__
  