Apple Push Notifications (APN) service server side Python 2 script in iOS - ios

I have configured my iOS application with Apple Push Notification (APN) service enabled. I was able to send notifications to devices with PHP and Python 3 scripts. I tested both on local server with local machine. But now I need to write the script in Python2.
Below is the script I've written and when I run this I get nothing. Neither a notification to my device nor error in command line.
import socket, ssl, json, struct
import binascii
import os
deviceToken = 'my_device_tocken_without_spaces'
thePayLoad = {
'aps': {
'alert':'My first push notification!',
'sound':'default'
}
}
theCertfile = 'ck3_2.pem'
theHost = ( 'gateway.sandbox.push.apple.com', 2195 )
data = json.dumps( thePayLoad )
theFormat = '!BH32sH%ds' % len(data)
theNotification = struct.pack( theFormat, 0, 32, deviceToken, len(data), data )
ssl_sock = ssl.wrap_socket( socket.socket( socket.AF_INET, socket.SOCK_STREAM ), certfile = theCertfile )
ssl_sock.connect( theHost )
ssl_sock.write( theNotification )
ssl_sock.close()
What did I miss? How can I check where is the mistake happen?
I ran PHP script in localhost using XAMPP and I ran Python script in command line because I was unable to set-up Python with XAMPP which I already posted a question here.

you may consider https://github.com/djacobs/PyAPNs that wrapped lot of useful features, including:
error handling
support enhanced message format and auto resend messages which are sent before error response
non-blocking ssl socket connection with great performance

I think there's nothing wrong with your code. You can try adding following lines after ssl_sock.connect( theHost )
print repr(ssl_sock.getpeername())
print ssl_sock.cipher()
print pprint.pformat(ssl_sock.getpeercert())
Which will print information about ssl of your connection.
Alternatively you can create a sample server and change the connections in your client and test against the server. http://carlo-hamalainen.net/blog/2013/1/24/python-ssl-socket-echo-test-with-self-signed-certificate

You imported binascii, but you forgot to use it.
Convert the token and json data to byte arrays, e.g.:
deviceToken = binascii.a2b_hex('my_device_tocken_without_spaces')
and
data = json.dumps(thePayLoad, separators=(',', ':'), ensure_ascii=False).encode('utf-8')

Related

How do I publish a stream of varying data to a MQTT broker, using micropython

I'm trying to create a basic weather station using a Raspberry Pi Pico W. I'm using a pimoroni pico explorer board and a BME280 breakout. I have been able to get the pico to publish to a topic and it will send a message when a single button is pressed, but I'm struggling to get it to publish temperature and humidity values rather than just a message.
I think I've worked out where the problem lies, but I don't know enough about micropython to be able to work out how to fix this issue.
I started with this code, to get the message button pressed when I pressed a button connected to the pico.
mqtt_server = 'broker.mqttdashboard.com'
client_id = 'bigles'
topic_pub = b'cherub'
topic_msg = b'Button Pressed'
Then I changed the topic message to be bme280.read as I figured that would give me 3 values and then I can go from there.
My initial thought process was that because the topic_msg is publishing a statment surrounded by '', it's just going to publish exactly whats between those quotes, right? So lets just remove the brackets and have:
topic_msg = bme280.read()
because it need to publish those values. Then I got the error code
Traceback (most recent call last):
File "<stdin>", line 17
SyntaxError: invalid syntax
So I tried topic_msg = (bme280.read()), but got invalid syntax again
Than I tried
temp = bme280.read()
topic_msg = 'temp'
Resulting in the message "temp" appearing in my broker.
I've tried defining temp as a function, only to be told that it has no len(). I tried addign len, using example code from the internet. It didnt work. I am out of ideas, can anyone suggest anything? Any resources, solutions, suggested google gterms ect, like I said, I'm really new to this. Thanks
Full code with my current edits:
import time
from breakout_bme280 import BreakoutBME280
from pimoroni_i2c import PimoroniI2C
from pimoroni import PICO_EXPLORER_I2C_PINS
i2c = PimoroniI2C(**PICO_EXPLORER_I2C_PINS)
bme = BreakoutBME280(i2c, address=0x76)
import network
import time
from umqtt.simple import MQTTClient
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("i can hear what u sayin","12345678")
time.sleep(5)
print(wlan.isconnected())
def temp
temp = bme.read()
mqtt_server = 'broker.hivemq.com'
client_id = 'bigles'
topic_pub = b'Temp'
topic_msg =
def mqtt_connect():
client = MQTTClient(client_id, mqtt_server, keepalive=3600)
client.connect()
print('Connected to %s MQTT Broker'%(mqtt_server))
return client
def reconnect():
print('Failed to connect to the MQTT Broker. Reconnecting...')
time.sleep(5)
machine.reset()
try:
client = mqtt_connect()
except OSError as e:
reconnect()
while True:
if bme.read():
client.publish(topic_pub, topic_msg)
time.sleep(5)
else:
pass
# Following lines are incorrect- incorrect syntax
# def temp
# temp = bme.read()
mqtt_server = 'broker.hivemq.com'
client_id = 'bigles'
topic_pub = b'Temp'
topic_msg = str(bme.read()) # convert received value into string
Also, in your while loop, you publish the same previously recorded value topic_msg and never read into it again.
Also, move out sleep time.sleep(5) outside if, into loop
Also, suggestion to fix wifi part:
wlan.connect('wifi', 'pass')
while not wlan.isconnected():
pass
print("Connected:", wlan.ifconfig())

Modem AT commands, unable to get into data mode (PPP)

I have a simcom7600 modem which I am trying out via AT commands.
I was able to use AT commands to setup the modem, and connect to an MQTT broker and exchange messages. Now I am trying to figure out how I can do something similar, but then with my own TCP/IP stack. Before diving into the deep there, I would like to confirm that I can get into data mode (PPP) which I am not able to, it seems.
I attached my modem (AT+CGATT=1), and activated it (AT+ACACT=1,1). I verified that I have a carrier/provider (AT+COPS?).
So I thought I was all set to send the ATO (online) commands. But it returns NO_CARRIER every time I try. I have no idea what I am doing wrong.
The logging that confirms above statements:
AT+COPS?
Sending command: AT+COPS?
AT+COPS?[CR][CR][LF]+COPS: 0,0,"NL KPN simyo",7[CR][LF][CR][LF]OK[CR][LF]
AT+cgatt?
Sending command: AT+cgatt?
AT+cgatt?[CR][CR][LF]+CGATT: 1[CR][LF][CR][LF]OK[CR][LF]
AT+cgact?
Sending command: AT+cgact?
AT+cgact?[CR][CR][LF]+CGACT: 1,1[CR][LF]+CGACT: 2,0[CR][LF]+CGACT: 3,0[CR][LF][CR][LF]OK[CR][LF]
ATO
Sending command: ATO
ATO[CR][CR][LF]NO CARRIER[CR][LF]
PS: the [CR][LF] stand for resp. \r and \n, I replace them before I log for ease of reading.
I obviously have to supply more info to the modem, but from this manual I can't seem to figure out which commands I miss, and how I could validate step by step that I am on the right track.
I found this nice document. I'll share it here in case somebody else struggles with this as well.
When I send the following commands:
ATZ (reset)
ATE0 (disable echo)
AT+CGREG? (check registration to PDP network)
AT+CGDCONT=1,"IP","internet" (set APN for my provider, they expect the string "internet")
ATD*99# (start data mode, aka PPP)
then I can break out and move back into PPP with the following commands:
+++ (send + character, wait for 700ms, send + character, wait for 700ms, send + character) => back to AT command mode
ATO (back to data mode)
NOTE: the APN your provider expects, is I think in all cases an easy Google. Your provider will most likely explain how to manually set your APN in case your phone won't do it automatically.

change trace log format in emqtt message broker

I am using emqtt message broker for mqtt.
I am not a erlang developer and has zero knowledge on that.
I have used this erlang based broker, because after searching many open source broker online and suggestions from people about the advantage of erlang based server.
Now i am kind of stuck with the out put of the emqttd_cli trace command.
Its not json type and if i use a perl parser to convert to json type i am getting delayed output.
I want to know, in which file i could change the trace log output format.
I looked on the trace code of the broker and found a file src/emqttd_protocol.erl. An exported function named trace/3 has the code that you need.
Second argument of this function, named Packet, has the information of receive & send data via broker. You can fetch required data from it and format according to how you want to print.
Edit : Sample modified code added
trace(recv, Packet, ProtoState) ->
PacketHeader = Packet#mqtt_packet.header,
HostInfo = esockd_net:format(ProtoState#proto_state.peername),
%% PacketInfo = {ClientId, Username, ClientIP, ClientPort, Payload, QoS, Retain}
PacketInfo = {ProtoState#proto_state.client_id, ProtoState#proto_state.username, lists:nth(1, HostInfo), lists:nth(3, HostInfo), Packet#mqtt_packet.payload, PacketHeader#mqtt_packet_header.qos, PacketHeader#mqtt_packet_header.retain},
?LOG(info, "Data Received ~s", [PacketInfo], ProtoState);

Symfony mailer: Swift_TransportException between message sending

On a current project which I'm currently working, i have a symfony task that runs some mass data insertion to database and runs it for at least half an hour.
When the task starts a mail notification is sent correctly, the problem is that at the of the task execution we can't send another mail to notify about the end of processing.
The mailer factory is currently configured with the spool delivery strategy but, in this specific situation, we desire to fire a notification immediately, using the sendNextImmediately() method.
I'm are getting the exception:
[Swift_TransportException]
Expected response code 250 but got code "451", with message "451 4.4.2 Timeout - closing connection. 74sm1186065wem.17
"
and the flowing error on php log file:
Warning: fwrite(): SSL: Broken pipe in /var/www/project/lib/vendor/symfony/lib/vendor/swiftmailer/classes/Swift/Transport/StreamBuffer.php on line 209
Can anyone give some help?
Is there any way that i can perhaps refresh symfony mailer to establish a new connection?
Doing a Symfony2 project, I ran across this failure too. We were using a permanently running php script, which produced the error.
We figured out that following code does the job:
private function sendEmailMessage($renderedTemplate, $subject, $toEmail)
{
$mailer = $this->getContainer()->get('mailer');
/* #var $mailer \Swift_Mailer */
if(!$mailer->getTransport()->isStarted()){
$mailer->getTransport()->start();
}
$sendException = null;
/* #var $message \Swift_Message */
$message = \Swift_Message::newInstance()
->setSubject($subject)
->setFrom($this->getContainer()->getParameter('email_from'))
->setTo($toEmail)
->setBody($renderedTemplate);
$mailer->send($message);
$mailer->getTransport()->stop();
//throw $sendException;
}
For Symfony1 Users
My guess was that the connection was being hold for too long (with no activity at all), causing an ssl connection timeout.
For now, the problem can be solved by stopping the Swift_Transport instance and starting it again explicitly, just before sending the second message.
Here is the code:
$this->getMailer()->getRealtimeTransport()->stop();
$this->getMailer()->getRealtimeTransport()->start();
$this->getMailer()->sendNextImmediately()->send($message);
I had exactly the same problem and above solutions were very helpful, but there is one thing I had to do differently: order.
$this->getMailer()->sendNextImmediately()->send($message);
$this->getMailer()->getRealtimeTransport()->stop();
It didn't worked for me if I tried to stop Transport before sending message (connection timeout was already hanging). Also You don't need to run getRealtimeTransport()->start() - it will be started automatically.

How to send a push notification using Erlang?

I'm trying to send a push notification to APNs using Erlang.
This is the code I came up with so far:
-module(apnstest2).
-export([connect/0]).
connect() ->
application:start(ssl),
ssl:seed("someseedstring"),
Address = "gateway.sandbox.push.apple.com",
Port = 2195,
Cert = "/path/to/Certificate.pem",
Key = "/path/to/Key.unenc.pem",
Options = [{certfile, Cert}, {keyfile, Key}, {mode, binary}],
Timeout = 1000,
{ok, Socket} = ssl:connect(Address, Port, Options, Timeout),
Token = "195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03",
Payload = "{\"aps\":{\"alert\":\"Just testing.\",\"sound\":\"chime\", \"badge\":10}}",
TokenLength = length(Token),
PayloadLength = length(Payload),
Packet = [<<0:8, TokenLength, Token, PayloadLength, Payload>>],
ssl:send(Socket, list_to_binary(Packet)),
ssl:close(Socket).
The code doesn't take advantage of Erlang's concurrency but is just a prototype. I only want to test if I can send the push in the most simple way.
I think the problem is in the packet being sent to the APNs.
This is the binary format of a push notification:
alt text http://developer.apple.com/IPhone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Art/aps_provider_binary.jpg
How should I create such a packet in Erlang?
Could someone please take a look at my code and tell me where the problem is?
Also I used Erlang's SSL application to create the connection and send the data and I don't know if this is the problem or the packet.
Thanks!
To start with, there is no need for creating a list of a single binary and then calling list_to_binary/1 on it. You can just send the binary itself.
Also, make sure the field lengths and values are appropriate according to the protocol:
TokenLength = 32 = length(Token),
Packet = <<0:8, TokenLength:16/big, Token, PayloadLength:16/big, Payload>>,
ssl:send(Socket, Packet),
Now that we have gotten this far, we will see that length(Token) is in fact 64, not 32:
You forgot to convert the hex string for Token to a binary, so you are sending a 64 byte hex character string instead of 32 binary bytes.
So... making Payload a binary from the start, and making Token a numeric constant, you can do something like the following:
Payload = <<"{\"aps\":{\"alert\":\"Just testing.\",\"sound\":\"chime\", \"badge\":10}}">>,
PayloadLength = size(Payload),
Packet = <<0:8, 32:16/big,
16#195ec05a962b24954693c0b638b6216579a0d1d74b3e1c6f534c6f8fd0d50d03:256/big,
PayloadLength:16/big, Payload/binary>>,
ssl:send(Socket, Packet),
Thanks to Christian for pointing out a number of mistakes in the former revisions of this answer.
I see two mistakes:
Token should be passed in binary and not in hex ascii.
You can't use the binary syntax to turn lists into binaries.
For parsing hex to an integer and then down to binary use something like this:
Token = "dead",
TokenNum = erlang:list_to_integer(Token, 16),
TokenBin = <<TokenNum:32/integer-unit:8>>,
Build the protocol packet with something like this:
TokenBin = ...,
Payload = <<"Payload">>,
PayloadSize = byte_size(Payload),
Packet = <<0:8, 32:16, TokenBin/binary, PayloadSize:16, Payload/binary>>,
Try use a simple library epns(Erlang Push Notifications)
This library can send push notification as APNS and FCM by Erlang side. How use epns(Erlang Push Notifications) library - you can read in README.md. This liblary can used as 3-rd party in project, or you can run it locally for see how this library works:
$ git clone https://github.com/vkatsuba/epns.git
$ cd epns
$ make
Retested on Erlang 20~21

Resources