Sunday, March 25, 2018

Ham Solo: ESP8266 Based Amateur Radio Simplex Confirmation Project

Note:  As presented this project requires a FCC Amateur Radio license.  Amateur Radio is about experimentation.   Even still you must be versed in the band plan and stay away from local repeater stations, stay in accordance to FCC Amateur Radio rules such as 97.201(a), 97.201(b), 97.213(a), 97.215, 97.3(a)(7), and likely a few others.  Even after following all those rules, nobody likes to hear a bunch on random DTMF tones so keep your transmissions short and infrequent.
Most Amateur (or ham) radio operators have wondered how or if their signal is getting received.  After getting a YES/NO answer they may want to decrease power, try a different antenna set up, or change location.  The challenge with this can be a willing participant on the receive side that has promised to remain perfectly still and listen for hours.  If you have a friend or XYL willing to do that then consider yourself fortunate.  For all the others there is this project.
The rig is pretty straight forward and explained in the image above.
   - From the field a DTMF tone is transmitted on a frequency that "the shack" is tuned to.
   - If the radio in the shack hears the DTMF tone it is decoded with this module.
   - Code running on an ESP8266 turns the decoded tone "to English" and sends a SMS text message via IFTTT.
   - If the shack received everything you will get a confirming QSL SMS on your smartphone.
It's all quick and simple.  It takes only a 250 mSec or so transmission time and a delay of maybe 2 seconds to get the confirming QSL SMS.  The short video below gives a good explanation:

Want to build your own?  No problem.
   1st:  Get a FCC Amateur Radio license; it's not hard and is an extremely interesting hobby.
   2nd: Buy some radios (costs range from $30 to infinity).
   3rd:  Buy the DTMF module and an ESP8266.
   4th:  Set up a free IFTTT account for the SMS texting.
   5th:  Hook it all up as shown in the image at the top of this page.
   6th:  Load the source code below into your ESP8266 (you will need the Arduino IDE).
   7th:  Be respectful of the rules and test away.
Before showing the ESP8266 source code here's a short video using 5 of the 8 channels on the Tektronix MSO5 (which is bad ass!!!) to monitor the signals coming off the DTMF module.
The (short/simple) ESP8266 source code is below.  If you duplicate the project or this motivates you to get your FCC Amateur Radio license let us know:
 *  HamControl
 *  MARCH2018
 *  WhiskeyTangoHotel.Com
 *  This project as described requires a FCC Amateur Radio License!!!!!! 
 *  Be aware of all FCC license and regulation retrictions before use!!!
 *  Follow local band plan and Federal regulations!!!!!!!!!!!!!!!!!!!!!!
 *  Go ahead and get your license.  It's a fun hobby.  See:
 *  HamControl:
 *  Use DTMF Tones to control ESP8266 via ham radio.
 *  Primary application was to confirm simplex signal Tx/Rx for antenna testing.
 *  When a DTFM is detected a SMS is sent your cell phone for field comfirmation.
 *  For DTMF DeCode: SMAKN® XD-61 MT8870 (~$10 USD)  
 *  NOTE:  For Baofeng set volume to ~80%
 *  uC setting for Ardunio IDE (ESP8266 with WiFI)
 *  NoderMCU 1.0 (ESP-12E Module), 80MHz, 921600, 4M (3M SPIFFS)

// For the Wireless
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

// WiFi Connection Information
const char* ssid = "Your-SSID-Here";           // PRIVATE: Enter your personal setup information.
const char* password = "Your-WiFi-PW-Here";   // PRIVATE: Enter your personal setup information.
ESP8266WebServer server(80);

// IFTTT Information for WebHook widget
String MAKER_SECRET_KEY = "Your-IFTTT-PrivateKey-Here";   // PRIVATE: Enter your personal setup information. Your IFTTT Webhook key here
String TRIGGER_NAME_SMS = "HamControl_SMS";           // this is the Maker IFTTT trigger name to send SMS if a DTFM tone is recieved.
const char* host = "";
String url_SMS;       // url that gets built for the IFTTT Webhook sending SMS DTMF recieved confirmation.
String DTMF_String;   // used to covert numbers and *,#,A,B,C,D tones to a string value.

// Define and set up some variables
int DTMF;  // What key press was sent by the ham radio.

// Define ESP8266 pins
const int led = 2;  // Blue on board LED is on PIN-D4 (GPIO2) for this NoderMCU 1.0 ESP8266.  Blink it between reads
// Define pins from the DTMF Decoder to the ESP8266 GPIO
const int Q1 = 12;  // PIN-D6 SILK SCREEN LABEL
const int Q2 = 13;  // PIN-D7 SILK SCREEN LABEL
const int Q3 = 15;  // PIN-D8 SILK SCREEN LABEL
const int Q4 = 5;   // PIN-D1 SILK SCREEN LABEL
const int STQ = 4;  // PIN-D2 SILK SCREEN LABEL

// Program control variables
int logging = 1; // If 1 then send SMS.  Any other value (0) turns it off.  For debug, typically would be set = 1

void setup(void){ // This setup code is run once.
  pinMode(led, OUTPUT);     // set up the onboard Blue LED pin as an output.
  pinMode(Q1, INPUT);       // Q1-4 are the output signals from the DTFM IC
  pinMode(Q2, INPUT);       // that are feed into and read by the ESP8266
  pinMode(Q3, INPUT);
  pinMode(Q4, INPUT); 
  pinMode(STQ, INPUT);      // STQ is high when DTFM tone is detected
  Serial.begin(115200);     // turn on the serial monitor for debug
  // Is the WiFi working?
  WiFi.begin(ssid, password);
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print("Trying to connect to ");
    Serial.print(" on ");
    for (int x = 0; x < 20; x++) { // 
      digitalWrite(led, !digitalRead(led));  // toggle state of the on board blue LED. Shows program is trying to WiFi connect
      //Serial.println("Server Start blink loop....");
    } // endfor WiFi blink connect
  Serial.print("Connected to ");

  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
    Serial.println(" ");

  // Use WiFiClient class to create TCP connections for WiFi logging
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");  // Boo!!!

  Serial.println("HTTP server started");  // Woo Hoo!!!
  Serial.println(" ");
  Serial.println("Entering HamControl main loop. ");
  Serial.println("Waiting for DTMF... ");

void loop(void){    // Loop this code section until hell freezes over

  // The blue onboard LED will blink between to show prog is 'running'.
  digitalWrite(led, !digitalRead(led));  // toggle state of the on board blue LED.
  if (digitalRead(STQ) == HIGH) {  // If it HIGH then DTFM detected.  Let's get to work.
      Serial.println("DTMF Detected!!!");
      DTMF_String = "Could_not_decode_DTFM!";  // Should be overwritten below, but just in case Mr Murphry shows up...
      // Convert the four bit (Q1-Q4 read) to decimal values 1-9 to match the button pushed
      // 0=10, *=11, #=12, A=13, B=14, C=15, D=0
      DTMF = (digitalRead(Q4) * 8) + (digitalRead(Q3) * 4) + (digitalRead(Q2) * 2) + (digitalRead(Q1) * 1);
      DTMF_String = String(DTMF);
      if (DTMF == 10) {
          DTMF_String = "0";
      if (DTMF == 11) {
          DTMF_String = "*";
      if (DTMF == 12) {
          DTMF_String = "HASH";
      if (DTMF == 13) {
          DTMF_String = "A";
      if (DTMF == 14) {
          DTMF_String = "B";
      if (DTMF == 15) {
          DTMF_String = "C";
      if (DTMF == 0) {
          DTMF_String = "D";
      Serial.println("Key pressed: " + DTMF_String);     
      if (logging == 1) { // is SMS logging turned on?
          // Set up IFTTT Webhook Channel to send the SMS. 
          // Use WiFiClient class to create TCP connections for IFTT SMS
          WiFiClient client;
          const int httpPort = 80;
          if (!client.connect(host, httpPort)) {
            Serial.println("connection failed");
          // Build the IFTTT SMS url
          url_SMS = "" + TRIGGER_NAME_SMS + "/with/key/" + MAKER_SECRET_KEY+ "?value1=" + DTMF_String;
          Serial.println(" ");
          Serial.println("SMS payload to IFTTT.");
          client.print(String("POST ") + url_SMS + " HTTP/1.1\r\n" +
          "Host: " + host + "\r\n" +
          "Connection: close\r\n\r\n");
          Serial.println(" ");
          Serial.println("Logging is ON.");
          delay(1000);   // pause for webservices and to prevent double tap
          // and fast blink the blue onboard LED to show DTMF was recognized
          for (int x = 0; x < 100; x++) {
              digitalWrite(led, !digitalRead(led));  // toggle state of the on board blue LED
          } // endfor DFTM delay/blink                
      } else {
          Serial.println("Logging is OFF.");
          Serial.println(" ");
      } // endif/else logging 

      Serial.println("Waiting for DTMF... ");
  } //Endif STQ High?
  delay(250); // Delay for flashing on board BLUE program running status LED
} // void loop until hell freezes over