Sleep as Android and MQTT

I use Sleep As Android for both sleep tracking and my alarm clock. It works very well, combining these features into a “Smart wakeup period” that sounds your alarm at the optimal time in your sleep cycle to help you wake up. Beyond this, it has a lot of great features such as support for wearables and Tasker. There’s a small fee for the app, but it’s easily one of the best purchases I’ve made on Google Play.

Up until now, I’ve used Sleep as Android to trigger Tasker when my alarm goes off, and Tasker then triggers openHAB activities. The developers recently added MQTT to the list of integrations, so I decided to see how I could use it with openHAB. And as a result, I’ve cut Tasker out of the loop.

What can it do?

Sleep as Android can publish 26 different events, from “Sleep tracking started” and “Baby crying” to “Alarm dismissed” and “Snooze clicked”. It’s an impressive list, but personally all I care about is “Alarm started”. Smartly, the developers have made it so that you can select which events will get published.

Something that others might like is the “Smart period” event. This is a period of time before your alarm goes off when Sleep As Android starts collecting data to determine when it should wake you up. If you like the idea of turning on your thermostat or starting your coffee before you wake up, this could work well for you.

You could also set this up on multiple phones with different MQTT Topics and Client IDs, so that openHAB can distinguish between two different alarms. So if you and your significant other wake at different times, openHAB could react differently for each of you.

Unfortunately, Sleep As Android can only publish events to MQTT. It can’t receive commands through MQTT at this time, but I’ve asked the developers if this might be possible in the future.

Prerequisites

I’m running OH3, and this tutorial reflects that. If you’re running OH2, ask for help to get it working on your system. In either case, you’ll need:

  • A working MQTT broker (I’m using Mosquitto on my openHABian RPi4)
  • JSONPath Tranformation installed

Setting up Sleep As Android

  1. In Sleep As Android, go to Settings > Services > Automation
  2. Click the checkbox to enable MQTT.
  3. Fill in the URL to point it to your MQTT broker and provide credentials (if required). tcp://username:password@openhab:1883.

image

In this case, “openhab” is the name of my RPi4. You could also use the IP address (e.g. 192.168.1.xxx). 1883 is the port.

Note that there’s also a secure option, in which case you would replace tcp with ssl. However, that’s out of scope for this tutorial (translation: I don’t know how to do any of that).

If you want to send events from multiple phones, then change Client ID to be unique for each device.

Create a thing in openHAB

Add a Generic MQTT thing in openHAB, attached to your MQTT broker. I’ve used SleepAsAndroid as the Unique ID.

Now, create a single channel with the following parameters:

  • Channel identifier: Event
  • Label: Event
  • Channel Type: Text Channel
  • MQTT State Topic: SleepAsAndroid

The MQTT Command Topic is blank, since we can’t send commands to Sleep As Android.

Create an item

Finally, link the channel to a new string item. I’ve used the bedroom category for mine, because it kind of makes sense.

You now have a working item to receive events from Sleep As Android. Open the app on your phone, go back to MQTT settings, and press the “Test” button. You’ll get this in your log:

Item 'SleepAsAndroid_Event' changed from NULL to {"event":"Unknown"}

That’s great, but it’s kind of ugly. And it gets uglier when Sleep As Android sends an actual event:

Item 'SleepAsAndroid_Event' changed from {"event":"Unknown"} to {"value1":"1611764100000","value2":"","event":"alarm_alert_start"}

All we really need is the alarm_alert_start text in the event, so let’s fix that.

Transform the state with JSONPath

  1. Go back to your item, then click on the Event channel.
  2. Scroll down to Profile and select JSONPATH.
  3. In the “JSONPath Expression” field, type $.event.
  4. Save the change.

This will extract the data for the event and ignore everything else. Once again, click the “Test” button in the app. You should get this:

Item 'SleepAsAndroid_Event' changed from {"value1":"1611764100000","value2":"","event":"alarm_alert_start"} to Unknown

And the next time your alarm goes off, you’ll get alarm_alert_start.

What’s next?

From here, I’ll leave it to you to decide what you do with Sleep As Android. I use it to trigger my morning routine, which includes turning on my bedside light if it’s dark, turning on the thermostat if it’s cold, and casting a radio station to my Chromecast if it’s a weekday.

It’s worth noting that this will only work if your phone is on the same network as your MQTT broker. Personally, that’s exactly what I want. It means that my morning routine will only run when I’m at home, and not when I’m somewhere else.

I would love if the developers added a Command Topic so that I could also start sleep tracking from openHAB. For that, I’m still using Tasker as an intermediary.

I’ve also asked the developers how the value1, value2, and value3 codes are generated, as these might be useful for distinguishing between different alarms on a single phone (e.g. your weekday and weekend alarm). If they’re random, perhaps the developers will add add an alarm identifier to the payload.

I hope you found this interesting and/or useful!

12 Likes

Thanks for sharing this @rpwong :slight_smile:

I was never 100% satisfied with SaA and Tasker in combination.
So i switched to a cron based wake up routine, which is not really flexible for time changes.
This looks really promising (even without the ability to send commands to SaA) and i will give it a try to replace my cron based triggers with mqtt.

Extended events look also pretty useful.

1 Like

@Confectrician, I thought you might like it based on our previous conversation about SaA.

1 Like

@rpwong WOW thanks for sharing, this was very specific but very efficient and did exactly (first try) what i need.

1 Like

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.

I’ve been finding the Android app’s alarm integration to be spotty lately (I think the integration with SaA and the openHAB app is challenging) and I decided to implement this MQTT approach as a stop-gap (or maybe a permanent solution).

As I was following the guide, I wonder if it makes more sense to configure as a Trigger Channel as opposed to a String Channel. The messages published from SleepAsAndroid represent an event, not a state (though you could convert some of the start/stop paired events to a state). But if all you care about is the start of the alarm, you can treat that as an event.

If all you care about is the one event, just trigger the rule using a Thing trigger event (you don’t even need to check which one). If you do care, you can limit it to the “alarm_alert_start” event in the trigger or you can set up the transformation on the Channel to create a separate Channel for each event you care about (see MQTT 2.5 M1+ How to implement the equivalent to MQTT1 REGEX filters, though I think there’s a way to do it just using the JSONPATH transform).

I set it up as follows:

MQTT Trigger Channel:

UID: mqtt:topic:broker:sleepasandroid
label: SleepAsAndroid
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:broker:broker
location: Phone
channels:
  - id: event
    channelTypeUID: mqtt:trigger
    label: Event
    description: ""
    configuration:
      stateTopic: SleepAsAndroid
      transformationPattern: JSONPATH:$.event

Rule Trigger:

configuration: {}
triggers:
  - id: "2"
    configuration:
      thingUID: mqtt:topic:broker:sleepasandroid
      channelUID: mqtt:topic:broker:sleepasandroid:event
      event: alarm_alert_start
    type: core.ChannelEventTrigger

Like you, I have a morning routine that runs but only if it’s not already past sunrise.

That makes sense to me if you’re only using it as a trigger. I’m also using the BEFORE_SMART_PERIOD event to trigger some “before I wake up” actions like turning on my heating. I must have added that after writing this guide, or else I would have mentioned it.

I also have the SLEEP_TRACKING_STARTED and SLEEP_TRACKING_STOPPED events enabled in SaA, but I don’t think I’m actually using them for anything.

You can do that with any number of triggers too. With the same Thing Channel config the rule trigger for BEFORE_SMART_PERIOD would look like this:

configuration: {}
triggers:
  - id: "2"
    configuration:
      thingUID: mqtt:topic:broker:sleepasandroid
      channelUID: mqtt:topic:broker:sleepasandroid:event
      event: before_smart_period
    type: core.ChannelEventTrigger

In a .items file it would look like:

Channel mqtt:topic:broker:sleepasandroid triggered alarm_alert_start
Channel mqtt:topic:broker:sleepasandroid triggered before_smart_period

Those make more sense to include as a Switch Channel.

  1. Set up a REGEX filter (see link above) to only match on .*sleep_tracking_.*
  2. Chain that to the JSONPATH to extract the $.event.
  3. Then use the “on value” sleep_tracking_started and “off value” sleep_tracking_stopped.

Link that to a Contact Item (since it’s read only) or a Switch Item and that Item will be OPEN/ON after sleep tracking starts and OFF/CLOSED when sleep tracking stops.

It’s a little more complicated but the advantage is you’ll always have an Item that reflects the sleep tracking state, even if another event occurs later before sleep tracking stops (e.g. if you want to track both sleep tracking and REM, when REM starts it will wipe out the String Items state, losing the fact that sleep tracking started). You can of course then use that Item in other rules (e.g. don’t do X when sleep tracking is on). In addition, because it’s a switch/contact, it’s chartable, though I doubt OH’s charts would be better than SaA’s charts, but you could compare your sleep activity to stuff like temperature, light level, etc that SaA can’t do.

An alternative would be to create a rule that triggers on these started/stopped events and update the Switch/Contact Item based on which event happened (note event in Rules DSL, event.event in other languages will carry the extracted value, e.g. “before_smart_period”). But I think it’s cleaner to have it configured in the Thing.

1 Like

Thanks, that’s good to know. I haven’t used channel triggers very often in my rules, so I probably defaulted to “put the string in a string item”. As you note, the item is superfluous since it’s not necessary to store that information long-term. :wink: