Skip to content

OttoScript 1.0 Vision

qui3xote edited this page Jan 17, 2022 · 3 revisions

What will OttoScript look like when it's 'Finished'?

OttoScript is still in development, and I make no promises that everything below will come to be exactly as shown (particularly in terms of syntax), but this example shows where OttoScript is going.

INCLUDE ../otto_globals.otto
@home_mode = input_select.home_mode 

AUTOMATION motion_lights_off (@trigger)
UNIQUE SINGLE (NAME,TRIGGER)
WHEN kitchen.motion_sensors,
     living_room.motion_sensors,
     den.motion_sensors
 CHANGES TO 'off' FOR 30 MINUTES
 IF @home_mode in ('guest', 'vacation')
    PASS
 ELSE
    TURN OFF @trigger:domain.lights
 END

Breaking it down

Globals, Imports & Namespaces

INCLUDE ../otto_globals.otto
@home_mode = input_boolean.home_mode 
...
IF @home_mode in ('guest', 'vacation')

OttoScript will handle namespaces and imports in a way familiar to Python programmers. Variables defined outside of automations will be available as 'global' variables throughout the file. However, by default any manipulations to these variables inside an automation will only affect the local copy. 'Imports' will be handled using relative or fixed filepaths.

Automation names and behaviors

AUTOMATION motion_lights_off (@trigger)

Users will be able to name their automation (motion_lights_off) and specify variables that can be passed to it. How deep and/flexible this passed variable system is an open question, but at minimum the triggering entity will be made available and can be assigned to a variable (@trigger in the exammple). In the spirit of OttoScript, all of this will be optional.

Users should also be able to specify how they want their automation to behave, as in the second line: UNIQUE SINGLE (NAME,TRIGGER) In this example, only one copy of the automation can be active at one time, and if it's triggered a second time while the first is still active, the second will be ignored (SINGLE). The last argument indicates the scope of uniqueness - each trigger statement creates it's own unique function, so that motion_lights_off can be triggered simultaneously for the living_room, den and kitchen.

Triggers

WHEN kitchen.motion_sensors,
     living_room.motion_sensors,
     den.motion_sensors
CHANGES TO 'off' FOR 30 MINUTES

Triggers will support running the same operation on multiple entities by specifying a comma seperated list - the same behavior will be available in commands. Support for other trigger types (such as running at a specific time, or based on a specific event) will also be supported. It's an open question whether each trigger should require a new 'WHEN' statement, or just be another 'list' passed to when. Here's an idea of how time triggers will be written:

WHEN AT 07:30
WHEN 15 MINUTES BEFORE SUNRISE
WHEN AT 21:30:15 ON SUN, THU
WHEN EVERY 15 MIN

Data types, entities, and functions

OttoScript tries to abstract away as many technical details of how automations are executed in order to allow users to focus on what should be done. To that end, the language doesn't enforce any rules about what counts as an entity, or what naming conventions should be used. In the 1.0 example, the script uses kitchen.motion_sensors despite the fact that HomeAssistant (which is the only platform currently supported) doesn't support referencing entities by their area. It's up to the interpreter (such as ottopyscript) to turn OttoScript references into commands that HomeAssistant (or any other platform) can understand. The only thing enforced by OttoScript is that entities must have a domain (kitchen, light, lock, alarm_panel....) and an id ('ceiling_lights', 'front_door'), which are connected by a dot. Attributes are accessed by a :attribute. kitchen.lights:brightness, light.front_office_desk_lamp and starship.enterprise:redshirts are all perfectly valid as far as OttoScript is concerned.

OttoScript also tries to be approachable to non-programmers - which means that sharp distinctions between strings, lists, numbers and dictionaries are avoided, and the ability to manipulate those data types will probably remain limited. If an automation requires thinking about arrays, or how best to iterate over a dictionary, it's probably time write some Python (or whatever language you prefer). There's nothing, however, to stop an interpreter from providing access to functions defined in other languages in order to bridge the gap, making commands like this an option for the future:

CALL python.turn_on_every_third_light ON (light.first, light.second, light.third, light.fourth) WITH (brightness=30%)