diff --git a/plugins/core/package-lock.json b/plugins/core/package-lock.json index 2020d1e13..8ec4d2bdc 100644 --- a/plugins/core/package-lock.json +++ b/plugins/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@scrypted/core", - "version": "0.0.121", + "version": "0.0.122", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/core", - "version": "0.0.121", + "version": "0.0.122", "license": "Apache-2.0", "dependencies": { "@scrypted/sdk": "file:../../sdk", diff --git a/plugins/core/package.json b/plugins/core/package.json index 7c52067b9..63440ba91 100644 --- a/plugins/core/package.json +++ b/plugins/core/package.json @@ -1,6 +1,6 @@ { "name": "@scrypted/core", - "version": "0.0.121", + "version": "0.0.122", "description": "Scrypted Core plugin. Provides the UI, websocket, and engine.io APIs.", "author": "Scrypted", "license": "Apache-2.0", diff --git a/plugins/core/src/automation.ts b/plugins/core/src/automation.ts index f329388ce..ca68b8ad1 100644 --- a/plugins/core/src/automation.ts +++ b/plugins/core/src/automation.ts @@ -4,6 +4,7 @@ import { AutomationJavascript } from "./builtins/javascript"; import { Scheduler } from "./builtins/scheduler"; import { Listen } from "./builtins/listen"; import { scryptedEval } from "./scrypted-eval"; +import { AutomationShellScript } from "./builtins/shellscript"; const { systemManager } = sdk; export class Automation extends ScryptedDeviceBase implements OnOff { @@ -57,6 +58,10 @@ export class Automation extends ScryptedDeviceBase implements OnOff { const script = new AutomationJavascript(this, eventSource, eventDetails, eventData); script.run(action.model['script.ts']) } + if (id === 'shell-scriptable') { + const script = new AutomationShellScript(this, eventSource, eventDetails, eventData); + script.run(action.model['script.sh']) + } else { const device = systemManager.getDeviceById(id); if (!device) diff --git a/plugins/core/src/builtins/shellscript.ts b/plugins/core/src/builtins/shellscript.ts new file mode 100644 index 000000000..4c18438e5 --- /dev/null +++ b/plugins/core/src/builtins/shellscript.ts @@ -0,0 +1,29 @@ +import { Logger, EventDetails, ScryptedDevice } from "@scrypted/sdk"; +import { Automation } from "../automation"; +import child_process from 'child_process'; + +export class AutomationShellScript { + eventSource: ScryptedDevice; + eventDetails: EventDetails; + eventData: any; + log: Logger; + + constructor(public automation: Automation, eventSource: ScryptedDevice, eventDetails: EventDetails, eventData: any) { + this.eventSource = eventSource; + this.eventDetails = eventDetails; + this.eventData = eventData; + } + + async run(script: string) { + const cp = child_process.spawn('sh', { + env: { + EVENT_DATA: this.eventData?.toString(), + }, + }); + cp.stdin.write(script); + cp.stdin.end(); + cp.stdout.on('data', data => this.automation.console.log(data.toString())); + cp.stderr.on('data', data => this.automation.console.log(data.toString())); + cp.on('exit', () => this.automation.console.log('shell exited')); + } +} diff --git a/plugins/core/ui/src/components/automation/Automation.vue b/plugins/core/ui/src/components/automation/Automation.vue index 67a8185ab..9b7875dc8 100644 --- a/plugins/core/ui/src/components/automation/Automation.vue +++ b/plugins/core/ui/src/components/automation/Automation.vue @@ -220,9 +220,14 @@ export default { const ret = [ { id: "scriptable", - text: "Run Script", + text: "Run Javascript", component: "Scriptable", }, + { + id: "shell-scriptable", + text: "Run Shell Script", + component: "ShellScriptable", + }, ]; for (const id of Object.keys( diff --git a/plugins/core/ui/src/components/automation/InterfacePicker.vue b/plugins/core/ui/src/components/automation/InterfacePicker.vue index 51a9a11f8..7388209ec 100644 --- a/plugins/core/ui/src/components/automation/InterfacePicker.vue +++ b/plugins/core/ui/src/components/automation/InterfacePicker.vue @@ -32,6 +32,7 @@ import Unassigned from "../../interfaces/Unassigned.vue"; import Condition from "../../interfaces/automation/Condition.vue"; import Timer from "../../interfaces/automation/Timer.vue"; import Scriptable from "../../interfaces/automation/Scriptable.vue"; +import ShellScriptable from "../../interfaces/automation/ShellScriptable.vue"; import EventListener from "../../interfaces/EventListener.vue"; import OnOff from "../../interfaces/OnOff.vue"; @@ -47,7 +48,6 @@ import Program from "../../interfaces/Program.vue"; import ColorSettingRgb from "../../interfaces/ColorSettingRgb.vue"; import ColorSettingTemperature from "../../interfaces/ColorSettingTemperature.vue"; import Brightness from "../../interfaces/Brightness.vue"; -import { actionableInterfaces } from "./interfaces"; import Select2 from "../../common/Select2.vue"; function unassigned() { @@ -75,6 +75,7 @@ export default { Condition, Timer, Scriptable, + ShellScriptable, EventListener, OnOff, diff --git a/plugins/core/ui/src/interfaces/automation/Scriptable.vue b/plugins/core/ui/src/interfaces/automation/Scriptable.vue index c0ae2fffd..6cbaa7e80 100644 --- a/plugins/core/ui/src/interfaces/automation/Scriptable.vue +++ b/plugins/core/ui/src/interfaces/automation/Scriptable.vue @@ -92,11 +92,11 @@ export default { data() { return { scriptSource: { - filename: null, - script: null, + filename: "script.ts", + script: '', scriptTitle: "Script", language: "typescript", - monacoEvalDefaults: null, + monacoEvalDefaults: () => monacoEvalDefaults, }, }; }, @@ -122,10 +122,9 @@ export default { } else { this.scriptSource.filename = Object.keys(this.lazyValue).filter((k) => k !== "rpc")[0] || - "script.ts"; + this.scriptSource.filename; this.scriptSource.script = this.lazyValue[this.scriptSource.filename]?.toString(); - this.scriptSource.monacoEvalDefaults = () => monacoEvalDefaults; } const editor = monaco.editor.create(this.$refs.container, { @@ -151,7 +150,7 @@ export default { }); const f = this.scriptSource.monacoEvalDefaults?.(); - f(monaco); + f?.(monaco); }, eval() { this.device.eval({ diff --git a/plugins/core/ui/src/interfaces/automation/ShellScriptable.vue b/plugins/core/ui/src/interfaces/automation/ShellScriptable.vue new file mode 100644 index 000000000..f93fcb995 --- /dev/null +++ b/plugins/core/ui/src/interfaces/automation/ShellScriptable.vue @@ -0,0 +1,20 @@ +