fxbox / thinkerbell Goto Github PK
View Code? Open in Web Editor NEWA scripting engine for the Foxbox
Home Page: http://fxbox.github.io/thinkerbell/doc/foxbox_thinkerbell/index.html
A scripting engine for the Foxbox
Home Page: http://fxbox.github.io/thinkerbell/doc/foxbox_thinkerbell/index.html
Currently, the simulator lives in examples/
. This means that:
cargo test
;We should move the code of the simulator into its module of src/
and use it to write tests.
Once this transformation is complete, examples/simulator.rs
should pretty much be reduced to its current fn main()
.
Meta-bug: #2.
In this Highschool, when a wifi/broadband-enabled device enters or
is turned on in the exam perimeter, send a message to the desktop
server. Give as much detail as possible on where the device is, so
that the teachers can come and frown at offending student.
Can be expressed as
I need:
- a `wifi detector` (zero or more) with property `activity detected`;
- a `broadband detector` (zero or more) with property `activity
detected`;
- a `communication channel to an application` with capability `send data``?
1. When `activity detected` of `wifi detector` switches to true
do `send data` to `communication channel to an application`:
`sensor details` of `activity detected`
This application is meant to be attached to a specific front-end.
wifi detector
with property activity detected
;broadband detector
with property activity detected
.communication channel to an application
with capability send data
;FIXME: I'm not entirely sure about that one. This detector is meant to
be used with a specific front-end. What's the best way to specify
front-end? Do we want to be so generic that we can change front-end?
That sounds over-engineered, but I can't think of anything simpler atm.
The current implementation of lang.rs makes considerable usage of Arc
. I believe that most of these uses of Arc
be replaced by &'a
, for greater safety and speed.
Code might be harder to read, though.
For the moment, we don't really know how to handle the case where we have n sensors (e.g. 15 fire detectors), one of them causes a condition to be met (e.g. there's fire on the 5th floor) and we need to determine which one.
We need to fix this.
Now that we have a Taxonomy API, we should port our codebase to that API.
Meta-bug: #2
When the motion detector hasn't seen any movement in 10 minutes,
turn off the lignts.
Can be expressed as
I need:
- `motion detectors` (at least one) with property `is there motion`;
- `lights` (at least one) to `turn off`;
- `10 minutes countdown` to `start`, `stop`, with property `is done`.
1. When `is there motion` of `motion detector` switches to false
do `start` with `10 minutes countdown`;
2. When `is there motion` of `motion detector` switches to true
do `stop` with `10 minutes countdown`;
3. When `is done` of `10 minutes countdown` switches to true
do `turn off` with `lights`.
Note that this does not require any explicit state.
motion detector
, with property is there motion
;10 minutes countdown
, built-in, with property is done
.lights
, with capability turn off
;10 minutes countdown
(the same one), with capabilities start
, stop
Note that applications are sandboxed, so the 10 minutes countdown is
not visible by other applications.
Nothing new here.
In an Art museum, paintings are generally quite sensitive. Use light sensors detect use of flash. If a flash is detected, ring an annoying sound.
For the moment, we support only sending constant values to an effector. We would like to be able to send data that is taken from a sensor, e.g. send a picture taken from a device to another device.
Consider the case of a device that is both a sensor and an effector, e.g. a heater with a built-in temperature sensor. Now, consider a shop with 20 such devices. How can we write a trigger that will cause an action on the device that has detected the input?
Calls to fetch, send and watch now require a User
, which may be useful e.g. for WebPush. For the moment, Thinkerbell does not propagate the User, so we cannot use WebPush from a recipe. To fix this, we should store the User whenever we insert a recipe โ and propagate this to the Thinkerbell adapter.
@mcav, do you have time to handle this?
For the moment, we only check the bare minimum when receiving a script. We should implement type-checking on physical measures.
Need to investigate this.
Meta-bug: #2
If there are no more cookies on the shelves of the store, send a
message to the manager. Don't do this more than once per hour.
For the moment, we cannot write unit tests, as the dependencies towards the low-level library are hard-coded. We need to fix this.
The user command should have the priority over rules in case of conflicts.
Case 1
A rule says 'turn on the lights between 6pm and 7pm'.
If a user turns off the lights on 6:30pm, then the lights must not be switched back on by the engine.
Case 2
A rule says 'turn on the lights when the motion sensor detects activity'.
A user can turn off the lights after the motion sensor turned it on. The sensor will still turn on the lights after that.
If a server needs to be taken down for upgrades, we may need to save some state on behalf of the apps.
Meta-bug: #2 .
I would like to be notified when my mailbox flap is opened. Possibly with an email sending me a picture of the mailbox content, so that I could see if it's been filled with ads or if there's actual mail in there that I should go pick up.
Thinkerbell already supports virtual devices. We should take advantage of this to let us define scripts that simulate device inputs. This will make testing easier.
For the moment, we rely on Serde's #[derive(Serialize, Deserialize)]
. This is very convenient, but:
Piece-by-piece and bottom-up, we should:
Serialize
, Deserialize
manually;Deserialize
/Serialize
;We have an issue right now: when we create recipe and its source has problems (like mismatch of Range and ChannelKind) - the recipe is still created, but without source.
We'll need to parse the data from JSON to interact with a REST API. Also, it might simplify writing tests.
We need some kind of CRUD API for Thinkerbell.
Possibly something along the lines of:
impl<Env> ScriptManager<Env> {
/// Create a new script manager at a given path (if provided).
///
/// This directory will be used to load/store scripts. If the directory doesn't exist, attempt to create it or return an error.
fn new<F>(path: Option<String>) -> Result<Self, Error>;
/// Attempt to read, parse and launch the scripts at the given path, asynchronously.
///
/// If any script causes an error, report that script, but do not let that error prevent other scripts from being read/parsed/launched.
///
/// Only scripts that are enabled should be loaded.
fn load<F>(&self) -> HashMap<String, Result<(), Error>>;
/// Attempt to add a new script, asynchronously.
///
/// If the script can be parsed/compiled/executed, this script is immediately saved to the disk.
fn put<F>(&self, id: &String, source: &String) -> Result<(), Error>;
/// Attempt to enable/disable a script.
///
/// Disabling a script stops it and stores the information to disk.
/// Enabling a script attempts to start it and stores the information to disk.
fn set_enabled<F>(&self, id: &String, enabled: bool) -> Result<(), Error>;
/// Attempt to remove a script.
///
/// If the script is running, stop it. Either way, remove it from the disk.
fn remove<F>(&self, id: &String) -> Result<(), Error>;
}
Note that none of the methods should cause a panic, ever.
For a v2, we should also handle argument on_event
of Execution::<Env>::run()
, but this can wait for a followup.
edit Reworked with a sync API.
I would like to be informed if the door of the office has been left open for more than 1 minute.
Note that this has immediate applications, as this would be really useful in my office :)
Meta-bug: #2 .
I would like to have a log of when my cat entered/left the house, going through an electronic cat flap on the garden door, that reads the cat's microchip. Additionally, it could be nice to have a photo taken each time the cat enters the house, to see if the cat brought me a little present.
If there is a fire alarm, we want to be able to send to the control device the list of fire detectors that have detected fire.
Meta-bug: #2.
When I leave the house, if the oven is on, send me a message and
sound a pre-recorded message on the speaker close to the door.
Can be expressed as
I need:
- a `presence monitor` with property `has presence`;
- a `oven` with property `is on`;
- a `communication channel to user` to `send text message`.
1. When `has presence` of `presence monitor` is false
and `is on` of `oven` is false
do `send text message` with `communication channel to user`: "Your left
your oven on but there is nobody home."
presence monitor
, with property has presence
oven
, with property is on
communication channel to user
is a built-in pseudo device. Itsend text message
Implementing this may be difficult, since Web Push API are pretty much not implemented on mobie devices.
switches to
, again measures a state changeis
measure a current stateNote that the order of execution of the branches in the AND will be important to minimize energy use. We will want to be informed of "switches to", rather than hammering "is".
Consider the following script:
when state_1 of [device_1, device_2, ...] is ... do send state_1 of device_1 to ...
We will receive any meaningful update to state_1
each of the devices. Now, if the state_1
of device_2
changes and causes the condition to become true, we want to make sure that we are not using a stale value of state_1 of device_1
in the do
branch.
It would probably be convenient for the user (at least for demos) to be able to trigger a rule even if time constraints are not met.
Implementing a countdown as a device looks tricky, as this means:
Channel<Getter>
for each consumer, to avoid collisions on the same countdown;Moreover, the effort looks unnecessary, as we do not have other kinds of devices that support such situation yet.
One way to implement this would be to make countdowns specific to Thinkerbell, e.g. by adding an optional field since
to conditions. With this argument, a trigger is executed only if the conditions remain true for the entire duration.
Side-benefit: this may be useful for sensors that are a bit too sensitive.
For the moment, we accept blindly that a resource has a given capability. We should check this during the compilation phase.
Meta-bug: #2 .
During the day, temperature of the heater should be set to 19C, but
during the night, reduce the temperature of heaters to 16C.
Can be expressed as
1. When the value of `a channel "get time of day" of service "foxbox clock"` is above 7pm do
send `temperature: 16C` to `all channels "set temperature"`.
2. When the value of `a channel "get time of day" of service "foxbox clock"` is between 6am and 7pm do
send `temperature: 19C` to `all channels "set temperature"`.
For a simple script like this, the "I need" part can probably be inferred from the actual triggers.
_edit_ Updated to Taxonomy API.
This is a bug in Rust: rust-lang/rust#31603
We should remove this file on test start and stop. Otherwise, we can end up with weird test failures, as I just did.
@mcav Can you handle that, when you have time?
We pollute the code by manipulating usize
indices everywhere. Not nice.
Write a prototype that is able to detect whether a condition is met.
Not sure if this is the right place to put this but when scheduling things like lights, it would be nice to say things like:
Turn my outside lights on at sunset plus or minus a 30 minute random time interval.
Collect examples of use cases for Monitor scripting. Decide which are simple enough that we can implement them with Thinkerbell, and which would require a more powerful scripting language.
I have put together a template for filing such stories.
Meta-bug: #2
If any pollution sensor detects more than n1% of CO2 or n2% of CO,
etc. send a secure message to a web service.
When 2 or more rules perform actions on the same endpoint, conflicts may arise.
Rule 1
'Turn on lights from 6pm to 7pm.'
Rule 2
'Turn off lights when no presence is detected.'
Given these 2 rules, what should happen if no presence is detected at 6:30pm?
One of the possible ways to solve this issue is to introduce a priority factor into the rules.
When a state changes (time or no presence detected), all the rules will have to be computed starting from the one with the lowest priority. The end result will be a combination where less important rules action may be overridden by more important ones.
This is of course just an idea, but I can't really think of any other elegant solution.
Write a prototype that will be able to execute actions when a condition is met.
Meta-bug: #2
If the server room is humid, inform all admins.
Meta-bug: #2
When I am on vacation, if my bedroom door opens, I want to receive a
picture of whatever happened in my bedroom.
Can be expressed as
I need:
- a `door opening detector` with property `door is opened`;
- a `camera` with property `image`;
- a `communication channel to user` to `send text message` and `send image`.
1. When `door is opened` of `door opening detector` switches to true
do `send text message` with `communication channel with user`:
"Someone entered your bedroom"
do `send image` with `communication channel with user`:
`image` of `camera`.
door opening detector
, with property door is opened
;camera
, with property image
The camera is a weird case, since property image
can typically weigh several Mb.
communication channel with user
with capability send image
image
is most likely a blob (binary data + mime type). Theimage
of camera
image
of camera
is async. TheMeta-bug: #2 .
I would like to have a log of the date/time when people rang the doorbell.
Once fxbox/foxbox#127 has landed, we may end up with endless loops between Thinkerbell and Thinkerbell. That's pretty ugly, so we'll need a way to detect such loops and somehow deactivate the rules.
Cc @fabricedesre , @mcav .
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.