Search This Blog

Monday, 1 May 2017

Use Pushover notification with ESP8266

Pushover.net is a notification service with clients for Android, iOS and Web.


The idea is that you can send a message to the service and it pops up on everyone's mobile phone that has subscribed to your channel on that service. There are lots of these types of services with slightly varying sets of features.


I was after one with pre-built clients for both Android and iOS that was simple to use and uncluttered with features that I would be unlikely to use. It also had to be free or low cost for home use.


I wanted it for sending messages from an ESP8266 used for a driveway alarm.


Up to 7500 messages the Pushover.net service is free to send messages, each person just has to pay a small one off fee for the client.


Creating an account and setting up the app and distribution group and a few other bits needs no explanation. I also took a moment to create a suitable icon. The thing that took all of the time was finding out how to send messages to Pushover.net from the ESP8266.

I found a few examples but none of them worked for me. There were some libraries specifically for Pushover however most were either overly complicated or poorly documented. Some of the sample code was very useful and I'd like to thank everyone who has posted other work on this subject. It all helped.

I eventually found the problem and then worked out a solution. The issue was that the Pushover service required the messages to be encrypted when sending to groups. The documentation, for using secure messages from the ESP8266, is a bit lacking.




#include "ESP8266WiFi.h"

// Push notifications
const String NOTIFICATION_APP =  "yourappkeyxxxxxxxxxxxxxxxxxxxx";
const String NOTIFICATION_USER = "youruserorgroupkeyyyyyyyyyyyyy";  // This can be a group or user

// Notification server
void PushNotification(String message) {
  // Pushover requires encrypted messages when sending to groups or anyone other
  // than the owner of the app
  WiFiClientSecure https;
  // Form the string
  String parameters = "token=" + NOTIFICATION_APP + "&user=" + NOTIFICATION_USER + "&message=" + message;
  int length = parameters.length();
  if (https.connect("api.pushover.net", 443)) {
    Serial.println("Start posting notification: " + parameters);
    https.println("POST /1/messages.json HTTP/1.1");
    https.println("Host: api.pushover.net");
    https.println("Connection: close\r\nContent-Type: application/x-www-form-urlencoded");
    https.print("Content-Length: ");
    https.print(length);
    https.println("\r\n");
    https.print(parameters);
    // ==
    // Reply from the server:
    while(https.connected()) {
      while(https.available()) {
        char ch = https.read();
        Serial.write(ch);
      }
    }
    // ==
    https.stop();
    Serial.println("Finished posting notification.");
  }
}



The above code worked for me. It needs some improvements to avoid the wait time for Pushover to respond but shows the basic principles.


I could then easily get the messages to appear on my Android phone and Shelley's iPad.

==

Download:
Code extract to use HTTPS with Pushover.net (zip)

==

Better Technique:
The above code will pause for a considerable amount of time if it cannot connect to Pushover or has to wait for the reply. It is easier to demonstrate using the above sample but is not how my code will look in the finished solution.

The reply from the server is probably only useful for debugging so the whole while loop for the reply can just be removed.

The following sample is a better way to handle the connection without holding up the code.




#include "ESP8266WiFi.h"

// Push notifications
const String NOTIFICATION_APP =  "yourappkeyxxxxxxxxxxxxxxxxxxxx";
const String NOTIFICATION_USER = "youruserorgroupkeyyyyyyyyyyyyy";  // This can be a group or user

const String MSG_ALARMTRIGGERED = "TEST ALARM TRIGGERED!";

WiFiClientSecure https;
bool isSendPush = false;
String pushParameters;

void loop() {
  TestTrigger();
  UpdatePushServer();
}

void TestTrigger(){
  if (isSendPush == false && digitalRead(TRIG_PIN) == HIGH)
  {
      StartPushNotification(MSG_ALARMTRIGGERED);
  }
}


void StartPushNotification(String message) {
  // Form the string
  pushParameters = "token=" + NOTIFICATION_APP + "&user=" + NOTIFICATION_USER + "&message=" + message;
  isSendPush = true;
  https.connect("api.pushover.net", 443);
  //Serial.println("Connect to push server");
}

// Keep track of the push server connection status without holding 
// up the code execution
void UpdatePushServer(){
    if(isSendPush == true && https.connected()) {
      int length = pushParameters.length();
      //Serial.println("Posting push notification: " + pushParameters);
      https.println("POST /1/messages.json HTTP/1.1");
      https.println("Host: api.pushover.net");
      https.println("Connection: close\r\nContent-Type: application/x-www-form-urlencoded");
      https.print("Content-Length: ");
      https.print(length);
      https.println("\r\n");
      https.print(pushParameters);

      https.stop();
      isSendPush = false;
      //Serial.println("Finished posting notification.");
    }
}



In this sample, the initial connect method [https.connect("api.pushover.net", 443);] is stand alone. It does not wait for the response.
Then during each loop, if the connection has been started [isSendPush = true;] the update method checks to see if the server has connected [https.connected()]. Only once it is connected does it send the message and stop the connection.

==

8 comments :

Unknown said...

This is great! Thank you heaps!

John C Brown said...

I'm glad it's useful. Regards.

Unknown said...

Wow, thats great. Was looking for something like that. Any infos about the driveway alarm would be helpful, too.

John C Brown said...

I'll type up an article about the driveway alarm once it's working. At the moment I only have the outside trigger code. I'm working on the network code to talk to receivers inside the house.

Unknown said...

Thanks for at great project. Im pretty new to Arduino, but have bought a ESP8266 NodeMCUv3 board, witch I would like this to work on.
Anyone here, know how I can uploade this code to my ESP without getting:
Arduino: 1.8.4 (Windows 10), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 115200, 4M (3M SPIFFS)"

Archiving built core (caching) in: C:\Users\Henrik\AppData\Local\Temp\arduino_cache_272342\core\core_esp8266_esp8266_nodemcuv2_CpuFrequency_80,UploadSpeed_115200,FlashSize_4M3M_a7d0ff46daaea23f1b4101b29caaa6de.a
C:\Users\Henrik\AppData\Local\Temp\arduino_build_757123/arduino.ar(core_esp8266_main.cpp.o):(.text._ZL12loop_wrapperv+0x4): undefined reference to `setup'

C:\Users\Henrik\AppData\Local\Temp\arduino_build_757123/arduino.ar(core_esp8266_main.cpp.o): In function `loop_wrapper':

C:\Users\Henrik\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_main.cpp:56: undefined reference to `setup'

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board NodeMCU 1.0 (ESP-12E Module).

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

John C Brown said...

Sorry, I can't help with that issue.

Stinky Cat Food said...

how does it connect to wifi? I did something simaler with esp32 and I had to include my wifi name and password...?

John C Brown said...

I did the same. I tried a few bits of code to try to have a setup interface but I could not find a reliable solution. For my purposes, I hard coded the wifi login details.