Accelerating Home Automation at SmartThings with Rule Engine
By Vlad Shtibin
How long does it take for a light switch to turn on a light bulb? How about for the garage opener to start raising the door? How often does the switch not work? Does it still work when the internet is down? The average “not smart” home is fast and reliable. This is the challenge we took on when thinking through building our next generation of Automations.
In order to create a smart home that is able to meet these goals, we need to take advantage of both cloud services and hubs on the edge. This blog post describes the architecture behind the SmartThings Rules Engine that is used by the cloud and hub to power Automations on the SmartThings platform.
The following diagram conveys a high-level summary of what the SmartThings platform “does” with devices. Events—in the form of protocol specific messages (Zigbee, Z-Wave, and more)—are converted into a common format (which we refer to as the Capabilities) and used by SmartThings services. Commands from SmartThings to a device follow the same pattern, just in reverse.
Cloud vs. Local Devices
Device Communications can happen on the cloud or hub. This is mainly driven by the integration type: Wi-Fi integrations execute on the cloud with Cloud and Direct Connected Devices, while Zigbee, Z-Wave, and LAN integrations execute on the hub with Edge Drivers. We also need to provide the flexibility for unique situations, like SmartApp connected Cloud Devices or Hub Connected devices that do not follow published specifications. In these cases, we use the cloud for parsing.
Thought Experiment with Philips Hue
Our partnership with Philips Hue is a great example of an integration seamlessly executing across cloud and hub. For a bit of background: there are multiple ways to connect Philips Hue products to the SmartThings platform, creating a broad topology:
To summarize the topology, all input and output (I/O) is dependent on where the integration is deployed and all Rule evaluation logic is independent of the deployment location. With the above use cases in mind, we needed to cover the two main integration points:
- Event Delivery: ability to consume events and get device states.
- Command Dispatch: ability to send commands to devices, set location modes, and more.
Looking at the architecture, we had additional requirements for high reliability, memory efficiency, and low overhead for delivery. We decided to use a Rust based solution because it is memory efficient, reduced code duplication across surfaces, and easily integrated with our existing experience and Release Engineering infrastructure.
The following table summarizes the requirements in a bit more detail:
|Requirement||Description||Benefits of Rust|
|High Reliability||Ensures all events are picked up and evaluated and automations execute, regardless of origin on the hub or cloud||The type system and ownership model mitigates a large class of potential bugs, ensuring memory and thread safety|
|Memory Efficiency||This is extremely important for embedded devices (aka hubs) that run the Rules Engine||Small footprint and processor demand make it easy to run on hubs|
|Delivery Overhead||We needed to balance the quick delivery of features and availability of the cloud platform versus the long firmware cycles for embedded devices||Reduce feature implementation time, flexible with multiple deployment targets|
|SmartThings Engineering Compatible||Release Engineering at SmartThings is standardized, new features must work with existing tooling||Our Rust SMEs were able to leverage the rich ecosystem for integration with our CI/CD processes for deployment|
With the above requirements, topology, and architecture in mind, we created Rule Engine. The resulting application architecture is essentially as follows:
The brains of the Rule Engine that contains and is responsible for the majority of the Rule execution code, Hive has two main functions: expose an API to execute Rules and provide an interface for parent services to interact with the platform.
To reduce overhead, Hive is dedicated to executing Rules, trusting the parent service to provide contextual data needed for rule execution, such as device states or location modes. For example, when a parent service receives a device state change event, it invokes Hive to evaluate (for example, is equals condition true), and executes the Rule.
The cloud container for Hive and management of I/O functionality for cloud execution, this service is deployed to the cloud and listens to events from the SmartThings event pipeline. When events are consumed, Swarm invokes Hive to execute Rules. The implementation of Hive’s interface by Swarm is a set of HTTP clients that interact with the SmartThings API.
For example, when Hive requires a device state to evaluate is equals condition true, Swarm dispatches a GET request to the Device API and forwards the state to Hive. Similarly, when Hive needs to send a device command, Swarm dispatches a POST request to the Device API.
The container for Hive embedded on edge devices (aka Hubs), Drone invokes Hive to execute Rules when events are consumed locally on the Hub. To implement Hive’s interface, Drone uses a Rust API provided by services on the Hub (for example, HubCore). Today, this application is bundled with SmartThings hub firmware and listens to events from a dispatcher on the hub.
For example, when Hive requires a device state to evaluate is equals condition true, Drone calls into HubCore to retrieve the device state. Similarly, when Hive needs to send a device command, Drone calls a
sendDeviceCommand() function on HubCore’s Rust API.
End-to-End, the process looks something like this:
Rule: If Switch A is ON, set Switch B to ON
- User turns Switch A on
- Swarm (cloud) or Drone (hub) receives the ON event
- Swarm/Drone tells Hive to execute Rules with if Switch A is ON
- Hive evaluates the Rule Conditions and determines to be true
- Hive then evaluates Actions, set Switch B to ON
- Hive says, “send device command to switch B”
- Swarm/Drone receives “send device command to switch B” and executes the request
Our team has been very impressed with the capabilities of the Rust programming language and supporting libraries. In the cloud, a small cluster of Swarm applications is able to execute hundreds of millions of Rules per day, resulting in drastically reduced cost of SmartThings hosted automations. We are then able to deploy virtually the same codebase on an embedded device—with a negligible footprint—and execute consistent, low latency and reliable automations in users’ homes.
Since the initial launch, we have released new locally executing features with each new firmware update. Looking ahead, we are regularly adding new features to Rule Engine that can bring you more complex Automations. To learn more, check out our Rules API Documentation and sign up for SDC21 to participate in SmartThings sessions.