Justifications and removing debug code.

main
Oliver Kennedy 2023-06-05 11:58:39 -04:00
parent c0255bae0c
commit d4b7a5c493
Signed by: okennedy
GPG Key ID: 3E5F9B3ABD3FDB60
2 changed files with 41 additions and 5 deletions

View File

@ -1,6 +1,32 @@
## Shingle
Stream-based home automation.
Add reactive programming to your existing home automation toolkit.
## What
Attach to Home Assistant, MQTT, or another event source and write automations in normal Scala 3 using a normal text editor.
## Why?
Shingle was born out of frustration with the limited programming interfaces available on most popular frameworks.
* **Home Assistant** programming is done through YAML files or a GUI that mimics the YAML files, and a custom templating language. This is perfectly fine for simple if-this-then-that type tasks, but makes specifying complex conditions (e.g., "when either of two sensors changes, but debounce the signal") incredibly painful. The custom templating language is also rather frustrating.
* **MQTT** offers no programming framework. It's just a message bus, although admittedly an incredibly powerful one with extensive support across a multitude of languages.
* **Node.red** is conceptually very nice, offering a stream-based solution not unlike Shingle. However, it's also painful to get running and is based on the "move fast and break things" javascript ecosystem.
Shingle is designed to add sensible programming support to existing home automation buses like Home Assistant or MQTT.
* Shingle doesn't try to invent its own programming language. Write code in simple Scala 3.
* Shingle doesn't try to be a message bus. Shingle plugs into MQTT or Home Assistant.
* Shingle doesn't force you to use a crappy web-based editor. Use your existing code editor to write scripts, and Shingle will load them.
So what exactly does shingle provide:
* Library code for reactive (stream-based) programming.
* Library code for connecting to existing event buses (Home Assistant, MQTT) and entities (Hermes, MPD, REST endpoints).
* A 'loader' that lets you dynamically load, enable, and disable individual pipelines.
## Getting Started
@ -19,8 +45,8 @@ Create a folder `~/.shingle` and a file `~/.shingle/config.json`:
#### Example Script
Create a folder `~/.shingle/scripts/` and a file `~/.shingle/scripts/Test.scala`
```
TimeEvents.every(3.seconds)
.trigger { _ => println("Hi!") }
Timer.every(3.seconds)
.trigger { _ => println("Hi!") }
```
#### Run Shingle
@ -126,6 +152,16 @@ The [music player daemon](https://www.musicpd.org/). To use the MPD integration
* `MPD.savedPlaylist(name)`: List all songs in the specified saved playlist
* `MPD.append(path)`: Add the song at the specified path to the end of the playlist
## The Admin interface
More coming here eventually, but Shingle exposes a simple web interface for runtime management.
* `http://localhost:4000/api/modules`: List every available module (the contents of `~/.shingle/scripts` without the `.scala` extension).
* `http://localhost:4000/api/modules/[script]`: Show the contents of the specified script.
* `http://localhost:4000/api/modules/[script]/unload`: Disable all triggers created by the specified script.
* `http://localhost:4000/api/modules/[script]/load`: Disable all triggers created by the specified script and reload it.
## Compiling Shingle
#### Setup

View File

@ -88,12 +88,12 @@ object Module
val engine = new ScriptEngine()
if(logger != null){
val ctx = engine.getContext()
println(s"Replacing: ${ctx.getErrorWriter()}")
// println(s"Replacing: ${ctx.getErrorWriter()}")
ctx.setWriter(logger)
ctx.setErrorWriter(logger)
engine.setContext(ctx)
}
println(s"Replaced with: ${engine.getContext().getErrorWriter()}")
// println(s"Replaced with: ${engine.getContext().getErrorWriter()}")
try {
val result = engine.eval(
s"""net.okennedy.shingle.module.Module("$module") { implicit ctx =>