Hub Configuration API Documentation (VERSION 2)
This API can be optionally implemented on a server. (You don't need to implement it, if you just want to send data to the server.) You can not directly update a hub's settings, because they are sleeping most of the time. Instead you can indirectly update a hubs settings, using this server API. The server keeps a copy of the hub's settings, and when the hub logs in it will synchronize it's settings to the server, or update the server if its settings have changed, based hub configuration timestamps.
Jason Config Update API
API URLs
https://api.vegecloud.com/v2/hubconfig/in/<RouteKey>/
https://api.vegecloud.com/v2/hubconfig/out/<RouteKey>/
JSON Format
When the VegeHub contacts its reporting server, it sends all of its sensor readings, and checks the server's reply for JSON data. If the field "who_updated" is present in the JSON data of the server's reply, the VegeHub checks that field for a number from 0-2 to determine whether it should check for new configuration data.
Values for the who_updated field:
- 0: The server is indicating that it has no record of this VegeHub (based on its MAC address) and that the VegeHub should send a full dump of all of its stored settings.
- 1: Indicates that the server has settings stored for this VegeHub, and that they were last updated by the VegeHub itself. The VegeHub will only proceed with exchange of config information if it has new settings to send to the server.
- 2: Indicates that the server has settings stored for this VegeHub, and that they were last updated on the server side. The VegeHub will now proceed to an exchange of config information.
VegeHub Request of Configuration Data from the Server
If the Hub is updating it's configuration information from the server, it will request the
individual pieces of the config from the server. It will send its MAC address, its API key,
and an empty JSON object to indicate which piece of the config it is requesting.
The JSON data will look something like this:
{"mac": "ABCD1234","api_key": "qwertyuiop", "sensors":[]}
The empty "sensors" array indicates that the Hub wants the settings for the sensors. The
possible objects the
Hub may request are:
- "hub":{} - The hub is requesting the general settings for the hub. The server will reply with an object.
- "actuators":[] - Requesting an array of all actuator objects associated with this Hub. The server will reply with an array of objects.
- "sensors":[] - Requesting an array of all sensor objects associated with this Hub. The server will reply with an array of objects.
- "schedule_overrides":[] - Requesting an array of all schedule override objects associated with this Hub. The server will reply with an array of objects.
Once the Hub has sent a request for a specific part of the config, it will then wait for the
reply from the
server. The server's reply will be JSON data formatted as follows:
{"mac": "ABCD1234","api_key": "qwertyuiop", "updated": 1977-05-25T12:00:00Z, "sensors":[...an array of sensor objects...]}
The Hub will check the provided API key against its own to make sure that this data was intended
for it.
Timestamp Check
The hub will now do a timestamp check to see who has the more up-to-date settings. This is necessary in case settings have been changed on both the hub and the server before they've had a chance to synchronize. The Hub will take the settings of whichever source was changed more recently. It uses the "updated" field to get the server's timestamp. The timestamp is based on the UTC, and is in standard Javascript Datetime string formatting.
If the Hub determines that the server has the most recent settings for this piece of the config, it will proceed to processing the JSON object provided. The formatting for the individual objects is documented below in the Extended JSON structure. Note that the full structure should never be sent all at once, as the Hub's receive buffer is too small and it will be unable to process the data.
Once the Hub is done processing an object or array of objects that it has requested, it will request the next object or array of objects that it intends to check.
Wrapping Up
Once the Hub is done processing all objects that it requested, it will do a full dump of all of its settings to the server.
Whenever the server gets a settings dump, it should look for the "updated" field coming from the Hub and use the date provided as its new stored timestamp. Now when the Hub sends an update, the server should reply with a 1 in the "who_updated" field to indicate that its settings have come from the Hub.
If settings are changed on the server side, it should change its stored timestamp to indicate the current UTC time when the settings were changed, so that the next time the Hub checks in, the server's timestamp will reflect when changes were made to it. Whenever changes are made to the settings on the server side, the server should then reply with a 2 in the "who_updated" field when it gets updates from the Hub.
{
// Send these fields for the request
"api_key": api_key_str[16],
"mac": mac_address_str[16],
"route_key": route_key_str[16],
"api_version": api_version_str[8],
// When querying object arrays, create an empty object or array for each item you want filled.
// for example "hub":{}, "slots":[] would get the hub object and the slots array.
// The server will return the requested objects as the following json objects.
// The following request will get all fields: {"api_key": "XXXX","mac": "XXXX","hub":{},"slots":[],"actuators":[],"schedules":[]}
"updated": updated_timedate_str, // time of last configuration update to server db.
"who_updated": who_updated_int, // 0: needs updating by hub, 1: hub did last update, 2: web interface did last update.
"hub": {
"model": model_str[32], // "VG-HUB1","VG-HUB4","VG-HUB4-RELAY,"VG-SPRINKLER4","VG-SPRINKLER4-LATCH"
"firmware_version": firmware_version_str,
"firmware_url": firmware_url_str, // URL where the hub should look for firmware updates
"hw_revision": string(16);
"manufacture_date": date_string("YYYY-MM-DD");
"manufactured_by": string(16);
"utc_offset": utc_offset_int // in seconds.
"name": name_str[32], // name of hub
"sample_period": sample_period_int, // in seconds
"update_period": update_period_int, // in seconds
"blink_update": blink_update_int, // 0: don't blink, 1: blink
"report_voltage": report_voltage_int, // 0: don't report, 1: report voltage
"server_url": server_url_str,
"update_urls": ["url1","url2","url3"], // send copies of the update data to these urls - typically other local networks sensors.
"static_ip_addr": static_ip_addr,
"dns": dns,
"subnet": subnet,
"gateway": gateway,
"current_ip_addr": current_ip_addr, // the currently assigned IP Address. Only the Hub can set or write this.
"power_mode": power_mode_int // Hub is connected to- 0: battery power, 1: wall power.
"agenda":agenda_int, // 0: Sprinkler Mode, 1: Hub/Greenhouse mode
"onboard_sensor_poll_rate": onboard_sensor_poll_int, // (seconds) Rate that actuator conditions poll onboard sensors when active.
"remote_sensor_poll_rate": remote_sensor_poll_int // (seconds) Rate that actuator conditions poll remote/web sensors when active.
},
"sensors": [ // sensor input channels
{
"name": name_str[32],
"slot": slot_int, // 0 based.
"mode": mode_int, // 0: sensor, 1: edge
"warm_up": warm_up_float, // in seconds.
"pull_up": pull_up_int, // 0: no pull up, 1: use pull up.
"always_power": always_power_int, // 0: power to sensor not always on, 1: always on.
"update_on_trigger": update_on_trigger_int, // 0: don't update, 1: update on trigger.
"edge": edge_int, // 0: falling, 1: raising, 2: both.
"transform:" transform_int // 0: none, index into list of standard vegetronix sensors. Transforms the voltage into units, i.e. degrees.
},
],
"actuators": [ // relays, valves, pumps, etc.
{
"name": name_str[32],
"slot": slot_int, // 0 based index of the physical actuator on the board.
"type": type_int, 0: undefined, 1: latching, 2: On/Off, 3: PWM, 4: DAC.
"pulse_width": ms_int // duration of latching pulse in miliseconds
"polarity": int // 0: normal polarity, 1: reverse polarity. Normally the black valve wire is connected to VCOMMON on the sprinkler board.
"enabled": enable_int, // 0: disabled, 1: enabled.
"turn_on": turn_on_int, // 0: OFF, 1: ON
"start_time": start_time_str,
"period": period_int, // (seconds) Period between activation windows
"duration": duration_int, // (seconds) Duration of activation windows
"conditions": [
{
"type": type_int, // None:0, Onboard sensor: 1, Time: 2, Local network: 3, Web JSON: 4, VegeCloud: 5
"name": name_str[32],
"sequence": sequence_int, // operand order. 0 based.
"bool_operator": chain_int, // 0: none, 1: AND, 2: OR (chain to previous condition)
"slot": slot_int, // (Optional) sensor channel slot
"range_lower": lower_float, // (Optional)
"range_upper": upper_float, // (Optional)
"range_hysteresis": hysteresis_float, // (Optional)
"range_operator": operator_int, // (Optional) 0: greater than, 1: less than, 2: inside, 3: outside, 4: true, 5: false
"fallback": fallback_int, // (Optional) 0: FALSE, 1:TRUE - Target state to assume if unable to contact web condition
"url": url_str[256], // (Optional) Target URL for a web condition
"url_param": url_param_str[256], // (Optional) (Format: "\"samples\"[0].\"value\"") Key used to pull data out of returned JSON data
"start_time": start_time_str, // (Optional) (Format: "15:05") Start time for time condition.
"end_time": end_time_str, // (Optional) (Format: "15:05") End time for time condition.
"days_of_week": days_mask_int // (Optional) // 0: never, 1: sun, 2: mon, 4: tue, etc. 127: every day. Days of week mask for time condition.
}
]
},
],
"schedules": [
{
"name": name_str[32],
"idx": idx_int, // 0 based. index of the schedule
"enabled": enabled_bool, // 0: disabled, 1: enabled.
"mode": mode_int, // 0: calendar, 1: periodic.
"days_of_week": days_of_week_mask_int, // 0: never, 1: sun, 2: mon, 4: tue, etc. 127 every day.
"period": period_int, // time between starts in minutes.
"start_time": start_time_str,
"actions": [
{
"enabled": enabled_bool, // 0: disabled, 1: enabled.
"actuator_slot": actuator_slot_int, // index of the physical actuator on the board.
"duration": duration_int, // on time of actuator in minutes
}
]
}
],
"web_conditions": [ // length could be less than the number of actuators.
{
"actuator_slot": slot_int, // 0 based indicates the actuator it is tied to.
"name": name_str[32],
"condition_key": condition_key_str[16], // 0 based. index of the schedule
}
],
"schedule_overrides":[
{
"id": id_int, // unique identifier
"start_time": start_time_str, // override start time. The zero time of "0000-00-00 00:00:00" means immediate.
"duration": duration _int, // (seconds) how long to run actuator
"actuator_slot": actuator_slot_int, // 0 based index of the actuator.
"action_type": action_type_int // 1: on, 2: off, 3: cancel.
}
]
}
VegeHub Request to update Configuration Data on the Server
Example VegeHub and Server Transaction
Hub to server:
POST / HTTP/1.1
Cache-Control: no-store
Transfer-Encoding: chunked
Content-Type: application/json
{"api_key":"2813099150","id":"","mac":"F8F0056BB15D","status":null,"sensors":[{"slot":1,"samples":[{"v":0.332,"t":"2024-06-07T16:02:00Z"}]},{"slot":2,"samples":[{"v":0.329,"t":"2024-06-07T16:02:00Z"}]},{"slot":3,"samples":[{"v":0.467,"t":"2024-06-07T16:02:00Z"}]},{"slot":4,"samples":[{"v":0.063,"t":"2024-06-07T16:02:00Z"}]},{"slot":5,"samples":[{"v":9.015,"t":"2024-06-07T16:02:00Z"}]}]}
Server replies:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 17
Connection: close
{"who_updated":0}
End of transaction.
Hub sends new post to server containing config data:
POST /configin HTTP/1.1
Cache-Control: no-store
Transfer-Encoding: chunked
Content-Type: application/json
{"api_key":"2813099150","id":"","mac":"F8F0056BB15D","who_updated": 1,"updated":"2024-06-07T16:03:20Z","hub":{"model":"VG-HUB4","utc_offset":0...
Server responds:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 17
Connection: close
{"who_updated":1}
If you continue to send "who_updated":0, the hub will continue to send config responses forever, so we finish with a "who_updated":1.