Moved to a New Blog
Well, that didn't last very long. The moment I tried adding a Gist like so on my old blog,
<script src="https://gist.github.com/dmarlow/2ea49c00ebc2e4e8e951.js"></script>
and I wasn't able to upload, was the moment I realized I needed something a little more "fresh".
And now here we are. Migration was painless since I only had three articles. I wish hosting images were a bit easier, but I'm satisfied. I basically copied David Ebbo's site (after running into his article on moving to GitHub Pages).
- Dariel Marlow
Creating a Simple SMS App - HackerNews (hn)
As I was sitting around I wondered what the top post in HackerNews was. Sure, I could have installed one of hundreds, or thousands, of apps or news readers. I could have even fired up my mobile browser or navigated via a bookmark. However, I wanted to see what it'd take to create an SMS wrapper around HN. Why? More like, why not?!
Here it Goes
First things first, I create an SMS app on SMSCMD like this blog post describes. I basically support these types of commands:
- hn top [1-3] - ex: hn top or hn top 2
- hn new [1-3] - ex: hn new or hn new 3
If the count is omitted, only one result is returned. Try it now, send a HackerNews command (hn top) to +13109064555.
The body parsing and HN news fetching is basically all there is. Here's my regular expression to parse the command (I actually don't receive the text "hn" as that's the SMS app name and is forwarded to that handler):
I use HackerSharp to fetch the HackerNews articles. This is what my MQTT message received handler looks like:
That's all there is to it. The only special sauce there is shortening URLs so I don't waste precious SMS space and "x.Title.Head(30)" (it gets the first 30 characters and adds ellipsis if needed). Here's what I got when I sent hn top when writing this.
MiniLock - File encryption...
http://goo.gl/7XRRKB
76 pts - poolpool | 25 comments
- Dariel Marlow
Handling a Breakup
Let's face it, everything must come to an end. Even that MQTT connection of yours will eventually break up with you disconnect. In the world of MQTT, the client connects to the server. So, in the event of an inevitable disconnect, what should your client do? Grab some ice-cream and hunker down in bed waiting for the server to come crawling back? No, it's got to go out into the world and figure things out. So, how should it do it?
The Solution
The answer is: well, it depends. What sort of client are you? One who is power/CPU constrained or not? One who crumbles at the sight of a disconnection? Here are some strategies for handling disconnection.
Naive Reconnect
We could do something like this:
Create client
Register callbacks
TryConnect:
Loop forever
If not connected
Connect
Sleep X
TryConnect() // Attempt connection
That loop forever step could be a in its own thread, but there are still issues with this. First, we will check every X time interval and needlessly spin the CPU and use resources. Even in a power/CPU rich environment, this isn't the most ideal.
Self-Aware Reconnect
After some introspection and self-awareness, we reach the conclusion that we can do better. How about this:
Create client
Register callbacks
OnDisconnect Callback:
TryConnect()
TryConnect:
Loop while not connected
Connect
Sleep X
TryConnect() // Attempt connection
That's slightly better. We don't needlessly check unless we have to. We only loop when we're trying to connect. We use the disconnect callback handler to worry about connecting. This is essentially what's in the Sms2Mqtt GitHub repo.
Zenful
If we're a power/CPU critical, and packet conscious, app/device, we may need to take better care of how we do things. Spinning endlessly while trying to connect is a noble goal, but we can kill ourselves trying. We should probably introduce some sort of exponential back-off. This allows us to try to connect, and if the server isn't answering our calls, we don't want to seem overly eager, or desperate. It might give the wrong impression and we'll just get exhausted.
Create client
Register callbacks
OnDisconnect Callback:
TryConnect()
TryConnect:
Interval = X
Loop while not connected
Interval = Min(Interval * 2, Limit)
Connect
Sleep Interval
TryConnect() // Attempt connection
I think this gets me to a happy place. My client spends CPU cycles more efficiently and takes a break when it can't connect. I think a perfectly valid interval to begin with is 1 second. From there, it jumps up to 2, 4, 8, 16, 32, then 64 seconds (where I'd place the limit).
Until next time,
- Dariel Marlow
SMS Enabling Your App/Device
I recently wrote a small app for my brother-in-law. It's a simple console app that drives selenium to automate a web browser. Great, it works and it works pretty well. It sits there day and night doing its thing. Soon thereafter, my brother in law asked me to tweak it, to turn it off, to pause it or change some behavior. After thinking about this, I realized there must be a better way! I didn't want to write an app, wait for it to be published, then get him to install it. Let alone writing multiple versions to put into multiple app stores should he change phones. The next alternative was to make a web interface for it. I thought that it seemed a bit heavy. Plus, I would have to open a firewall port and add security. It just didn't feel right. Then, I realized that he already has something that can communicate with the app, his phone. Why not send a text message and control the app directly? So that's exactly what I decided to build and make available to others as well.
Introducing SMSCMD
SMSCMD allows you to control your app (or Arduino/Raspberry Pi/Gadgeteer/etc. device) remotely via SMS. It's super easy to setup. There's a free version that's more than capable of handling simple things that don't need attention ever day.
How it Works
It's basically an MQTT server that can take requests via SMS. I use Twilio to capture SMS messages via HTTP, then I dump those into MQTT.
Getting Started
Still with me? Great! First, you need to create an SMS app on SMSCMD to begin the process.
Names must be unique. The SMS Password can be left blank. This is an added level of control most users probably won't need or use. Specify your MQTT username and password. This is what you'll use to connect to the MQTT server.
There's a section that shows the connection information: Server: q.smscmd.net Port: 1883 Client ID: weather-app Use the username and password specified Sub topic: weather-app/cmds Pub topic: weather-app/reply
When you click on the connection example, you're shown this:
It's basically a "ready to copy & paste" python version. A C# version is available on GitHub.
Finally, there's a section to configure what you want your app/device to receive. Depending on your plan, you can choose only the phone numbers that are allowed to send commands. You can test things out before hitting "Add" as well.
Responding to a Command
You'll notice in both examples (Python and C#) that there's something in the handler for when command, or message, arrives to reply. The format is important. You must reply and specify the command ID you received. This is to ensure things are sent back to the proper source. Both examples are basically an echo application; it responds back the same thing it received.
The reply should be send to "
That JSON object needs to be serialized and encoded into bytes (depending on your MQTT client). In C# it looks like this:
I'll leave it up to you to find out what happens when you send something the site doesn't understand.
Thanks for reading!
- Dariel Marlow