Node.js client for the Rachio Smart Sprinkler controller
npm install rachio
const RachioClient = require('rachio');
const client = new RachioClient('[YOUR-API-TOKEN]');
- All calls are in the context of the api token used to instantiate the client
- All functions return native Promises unless otherwise noted
- All resource objects implement
.toPlainObject()
and.toJson()
functions that can aid in application / development / debugging. - Don't instantiate the Resource classes directly. Always get an instance from the
RachioClient
or returned from a method on another Resource instance. - There are often multiple ways to accomplish the same tasks in this library. For instance, the
RachioClient
provides entry points to every resource class provided you know the ids, but as you're learning and exploring the API, it might help to consider a relational approach, i.e., use theRachioClient
to getDevices
to getZones
, etc.
- RachioClient
- Device
- Zone
- MultiZone
- CurrentConditions
- CurrentSchdeule
- Event
- Forecast
- Person
- ScheduleItem
- ScheduleRule
This is the entry point for all of your interaction with the Rachio API. Most programs should start by getting an instance of the client using your Rachio Api Key.
const RachioClient = require('rachio');
const client = new RachioClient('YOUR-API-KEY');
// ... Do something useful
All subsequent code examples will presume you have an instance of RachioClient
assigned to the variable client
in the current application scope.
- a
Promise
to return anArray
ofDevice
objects
- Get a list of all Rachio devices associated with the API token
client.getDevices()
.then(devices =>
devices.forEach(d =>
console.log(`${d.name} : ${d.model} : ${d.id}`)));
Rachio-Garage : 8ZR2ULW : 2a5e7d3c-c140-4e2e-91a1-a212a518adc5
Rachio-Backyard : 8ZR2ULW : 8de4dbf6-7a52-43b0-9c18-7d074b868f67
- a
String
representing a device id
- a
Promise
to return aDevice
object
- Gets a device so that its properties can be inspected and actions can be performed upon it.
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device =>
console.log(`${device.name} : ${device.model} : ${device.id}`));
Rachio-Garage : 8ZR2ULW : 2a5e7d3c-c140-4e2e-91a1-a212a518adc5
As mentioned earlier, the RachioClient provides direct access to every resource class represented in the public API. More detail on how these work will be covered in the documentation for the individual resources
Returns information about the currently authenticated user
Retrieves a list of events for the given device id
The CurrentConditions
as reported by your Rachio's preferred PWS
The forecasted conditions reported between the start and end dates
Today's Forecast
for the device
Tomorrow's Forecast
for the device
Get all Zone
objects for the specified device
Gets the Zone
specified by the zoneId
Gets a new instance of MultiZone
for operations across multiple zones
Gets the ScheduleRule
for the given id
Gets the FlexScheduleRule
for the given id
- a
Promise
to return anArray
ofZone
objects
- Get a list of all zones associated with the
Device
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.getZones())
.then(zones =>
zones.forEach(z =>
console.log(`${z.name} : ${z.zoneNumber} : ${z.enabled} : ${z.id}`)));
Zone 1 - Front Door : 1 : true : ec47f4a6-5771-4d8f-834a-89bc7d889ea4
Zone 2 - Front West : 2 : true : f0e042bd-7ba1-4aba-bede-6d8b16857d3a
Zone 3 - Garage Front : 3 : true : f0e042bd-7ba1-4aba-bede-6d8b16857d3a
Zone 4 - Garage Side : 4 : true : 8de4dbf6-7a52-43b0-9c18-7d074b868f67
Zone 5 - Back Door : 5 : true : 1f3759cf-8722-4331-8859-aef4e328ce51
Zone 6 - Back Yard : 6 : false : 5bb1b267-7c0d-40a3-b532-d3b4e616c280
Zone 7 : 7 : false : 34c2b94a-2be0-46bd-83af-cc63daa8047c
Zone 8 : 8 : false : d8bd46d1-77ab-4c15-8aa1-b5a529897b37
- A
Promise
resolving totrue
if the device is currently watering - A
Promise
resolving tofalse
if the device is not currently watering
- Are any of the zones on the device currently watering?
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.isWatering())
.then(isWatering => console.log( isWatering
? 'The lunatic is on the grass'
: 'The lunatic is in my head'));
...Looking outside, I see zone 5 watering...
The lunatic is on the grass
true
- Tell the device to halt any currently running watering activity
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.stopWater())
.then(success => console.log(success));
true
- a
Promise
to return aZone
object that is currently watering. false
if no zone is currently watering
- Get me the zone that is watering right now
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.getActiveZone())
.then(activeZone => console.log( activeZone
? `The lunatic is in ${activeZone.name}`
: 'The lunatic is in my head'));
...Looking outside, I see zone 5 watering...
The lunatic is in Zone 5 - Back Door
- a
Promise
that resolves to aBoolean
dependent on the success of the operation
- Tell the device to stand-by and cease running any current or future scheduled activity
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.standbyOn())
.then(success => console.log(success));
true
- a
Promise
that resolves to aBoolean
dependent on the success of the operation
- Tell the device to resume all scheduled activity, if it was previously in stand-by mode
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.standbyOff())
.then(success => console.log(success));
true
- durationInSeconds (default = 1 day), a
Number
representing the number of seconds from now you would like the rain delay to persist
- a
Promise
that resolves to aBoolean
dependent on the success of the operation
- Set a rain delay for the next 8 hours
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
const duration = 28800; // 8 hours, in seconds
client.getDevice(deviceId)
.then(device => device.rainDelay(duration))
.then(success => console.log(success));
true
- a
Promise
that resolves to aBoolean
dependent on the success of the operation
- Cancel a previously set rain delay
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.rainDelayCancel())
.then(success => console.log(success));
true
- This is equivalent to calling
Device.rainDelay(0)
- startTime (optional), a
Number
representing the Unix time in milliseconds for which you would like to start your event filter- Cannot be a number < 28 days from present
- endTime (optional), a
Number
representing the Unix time in milliseconds for which you would like to end your event filter - filters (optional), an
Object
whose properties and values you would like to use as a filter for events.
- a
Promise
to return anArray
of deviceEvent
objects that match your specified filters
- Show me every time my
Device
has set a rain delay in the past week
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
const endTime = Date.now();
const startTime = endTime - 604800000; // 1 Week in millis
const filters = {
category: 'DEVICE',
type: 'RAIN_DELAY',
subType: 'RAIN_DELAY_ON'
};
client.getDevice(deviceId)
.then(device => device.getEvents(startTime, endTime, filters))
.then(events => events.forEach(e => console.log(e.toPlainObject())));
...
{ createDate: 1499458409090,
lastUpdateDate: 1499458409090,
id: '15117336-668c-4f74-a162-efc9c36f95ea',
deviceId: '2a5e7d3c-c140-4e2e-91a1-a212a518adc5',
category: 'DEVICE',
type: 'RAIN_DELAY',
eventDate: 1499458409090,
...
iconUrl: 'http://media.rach.io/icons/api/rain-delay-activated.png',
summary: 'Rain delay active until Saturday, July 8 02:13 PM',
subType: 'RAIN_DELAY_ON',
hidden: false,
topic: 'DEVICE' }
...
- I haven't seen great documentation on the possible event types / values. The best way to figure out what's available to you with Events is to just call
Device.getEvents()
and explore the data returned from your device.
- startTime (optional), a
Number
representing the lower-bound Unix time in milliseconds for which you would like to fetch the forecasts. Rounds down to 00:00 of the day represented by the timestamp - endTime (optional), a
Number
representing the upper-bound Unix time in milliseconds for which you would like to fetch the forecasts. Rounds up to 23:59 of the day represented by the timestamp - units (defaults to "US"), a
String
with the value ofUS
orMETRIC
, determining the forecast data representation
- a
Promise
to return anArray
of deviceForecast
objects that match your specified parameters
- See the next 3 days of forecast data for your device
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
const startTime = Date.now();
const endTime = startTime + 259200000; // 3 days in millis
client.getDevice(deviceId)
.then(device => device.getForecast(startTime, endTime))
.then(forecasts => forecasts.forEach(f => console.log(f.toPlainObject())));
...
{ localizedTimeStamp: 1500296400000,
precipIntensity: 0,
precipProbability: 0.1,
temperatureMin: 64.4,
temperatureMax: 91.4,
windSpeed: 4.34,
humidity: 0.55,
cloudCover: 0.31,
dewPoint: 51.8,
weatherType: 'partly-cloudy-day',
unitType: 'US',
weatherSummary: 'Partly Cloudy with Isolated Storms',
iconUrl: 'http://media.rach.io/images/weather/v2/active_partly_cloudy_day_2x.png',
icons: {},
calculatedPrecip: 0,
prettyTime: '2017-07-17T13:00:00Z',
time: 1500296400 }
...
- When called with no parameters,
Device.getForecast()
will return the next 14 days ofForecast
objects
- units (defaults to "US"), a
String
with the value ofUS
orMETRIC
, determining the forecast data representation
- a
Promise
to return aForecast
object for today
- units (defaults to "US"), a
String
with the value ofUS
orMETRIC
, determining the forecast data representation
- a
Promise
to return aForecast
object for tomorrow
- probabilityThreshold (defaults to 0.25), a
Number
representing the probability threshold beyond which to classify a Forecast as "rainy" - units (defaults to "US"), a
String
with the value ofUS
orMETRIC
, determining the forecast data representation
- a
Promise
to return the earliestForecast
object that it is projected to rain within the next 14 days
- units (defaults to "US"), a
String
with the value ofUS
orMETRIC
, determining the forecast data representation
- a
Promise
to return aForecast
object for tomorrow
- a
Promise
to return the parentDevice
to which this zone belongs
- I need to get from
Zone
objects, back toDevice
objects
const zoneId = 'f0e042bd-7ba1-4aba-bede-6d8b16857d3a';
client.getZone(zoneId)
.then(zone => device.getDevice())
.then(device => console.log(`${d.name} : ${d.model} : ${d.id}`));
Rachio-Garage : 8ZR2ULW : 2a5e7d3c-c140-4e2e-91a1-a212a518adc5
- a
Promise
to return aBoolean
,true
if the zone is currently watering,false
otherwise
- Tell me if a specific zone is watering.
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
client.getDevice(deviceId)
.then(device => device.getZones())
.then([zone1, zone2, ...rest] => zone2.isWatering());
.then(console.log);
I look out the window and see zone 2 watering...
true
- durationInSeconds (defaults to 60), a
Number
representing the minutes that this zone should water, beginning now.
- a
Promise
that resolves to aBoolean
dependent on the success of the operation
- Start a zone watering, right now
const zoneId = 'f0e042bd-7ba1-4aba-bede-6d8b16857d3a';
const durationInSeconds = 300;
client.getZone(zoneId)
.then(zone => zone.start(durationInSeconds))
.then(console.log);
true
- a
Promise
that resolves to aBoolean
dependent on the success of the operation
- Stop a zone that is currently watering
const zoneId = 'f0e042bd-7ba1-4aba-bede-6d8b16857d3a';
client.getZone(zoneId)
.then(zone => zone.stop())
.then(console.log);
true
- This is the same as calling
Device.stopWater()
, and as such it will also stop all other zones that may be currently watering or were scheduled for a manual run (i.e., from a MultiZone.start())
This class is used for operations that span multiple zones such as manually starting one or more zones for immediate watering. The best way to work with this class is to first obtain an instance from the RachioClient
as here:
...
const multi = client.multiZone();
...
Note that this function is synchronous and does not return a Promise
- zone, a
Zone
- orObject
with a propertyid
- representing the zone you would like to add to the multi zone operation - durationInSeconds (defaults to 60), a
Number
representing the minutes that this zone should water, beginning now.
- a
MultiZone
itself, allowing you to chain multipleadd()
calls together to compose your multi zone operation - Note that this function is synchronous and does not return a
Promise
- see
MultiZone.start()
below
- see
MultiZone.start()
below
- A
Promise
resolving totrue
if the operation is successful
- I want to water all of the zones on my device, immediately, for 5 minutes each
const deviceId = '2a5e7d3c-c140-4e2e-91a1-a212a518adc5';
const durationInSeconds = 300;
client.getDevice(deviceId)
.then(device => device.getZones())
.then(zones => zones.reduce((multi, zone) => multi.add(zone, durationInSeconds), client.multiZone()))
.then(multi => multi.start())
.then(console.log);
true
// Looking out my window, I notice each of the zones watering for 5 minutes, in numerical order
TODO: Documentation
To turn on debugging logs, set the environment variable DEBUG=rachio.*
when starting your nodejs process.
- Implement Webhook / Notifications API
- Better, friendlier date handling. The client-facing api doesn't have to be exclusively epoch-based.
- Better documentation and examples
- Explore packaging as a general javascript library (work from browser or node)
- Consider a transpiler to broaden support to older versions of Node.js
npm run mocha
Contributions to the 🍻 fund are much appreciated!
MIT License
Copyright (c) 2017 Jonathan Griggs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.