Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist last scene #83

Merged
merged 3 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
409 changes: 283 additions & 126 deletions backend/app/codegen/scene_nim.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion backend/app/models/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def new_frame(name: str, frame_host: str, server_host: str, device: Optional[str
rotate=0,
background_color="#ffffff",
device=device or "web_only",
log_to_file=None, # save the SSD by default
log_to_file=None, # spare the SD card from load
)
db.session.add(frame)
db.session.commit()
Expand Down
4 changes: 2 additions & 2 deletions e2e/generated/scenes.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is autogenerated

import frameos/types
import tables
import tables, options
import scenes/scene_color as scene_color
import scenes/scene_gradient as scene_gradient
import scenes/scene_ifElse as scene_ifElse
Expand All @@ -11,7 +11,7 @@ import scenes/scene_qr as scene_qr
import scenes/scene_split as scene_split
import scenes/scene_text as scene_text

let defaultSceneId* = "color".SceneId
let defaultSceneId* = some("color".SceneId)

const sceneOptions* = [
("color".SceneId, "Test Color"),
Expand Down
2 changes: 2 additions & 0 deletions e2e/state/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This changes too unpredictably in CI
scene.json
26 changes: 25 additions & 1 deletion frameos/src/frameos/runner.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var
lastPublicStates {.guard: lastPublicStatesLock.} = %*{}
lastPublicSceneId {.guard: lastPublicStatesLock.} = "".SceneId
lastPersistedStates = %*{}
lastPersistedSceneId: Option[SceneId] = none(SceneId)

proc setLastImage(image: Image) =
withLock lastImageLock:
Expand Down Expand Up @@ -91,13 +92,25 @@ proc updateLastPersistedState*(self: FrameScene) =
if hasChanges:
writeFile(&"{SCENE_STATE_JSON_FOLDER}/scene-{sanitizePathString(self.id.string)}.json", $persistedState)
self.lastPersistedStateUpdate = epochTime()
if lastPersistedSceneId.isNone() or lastPersistedSceneId.get() != self.id:
writeFile(&"{SCENE_STATE_JSON_FOLDER}/scene.json", $(%*{"sceneId": self.id.string}))
lastPersistedSceneId = some(self.id)

proc loadPersistedState*(sceneId: SceneId): JsonNode =
try:
return parseJson(readFile(&"{SCENE_STATE_JSON_FOLDER}/scene-{sanitizePathString(sceneId.string)}.json"))
except IOError:
return %*{}

proc loadLastScene*(): Option[SceneId] =
try:
let json = parseJson(readFile(&"{SCENE_STATE_JSON_FOLDER}/scene.json"))
if json.hasKey("sceneId"):
result = some(SceneId(json["sceneId"].getStr()))
lastPersistedSceneId = result
except IOError:
return none(SceneId)

proc renderSceneImage*(self: RunnerThread, exportedScene: ExportedScene, scene: FrameScene): Image =
let sceneTimer = epochTime()
let requiredWidth = self.frameConfig.renderWidth()
Expand Down Expand Up @@ -301,12 +314,23 @@ proc startMessageLoop*(self: RunnerThread): Future[void] {.async.} =
if waitTime < 200:
waitTime += 5

proc getFirstSceneId*(): SceneId =
if defaultSceneId.isSome():
return defaultSceneId.get()
let lastSceneId = loadLastScene()
if lastSceneId.isSome():
return lastSceneId.get()
if len(exportedScenes) > 0:
for key in keys(exportedScenes):
return key
return "".SceneId

proc createRunnerThread*(args: (FrameConfig, Logger)) =
{.cast(gcsafe).}:
var runnerThread = RunnerThread(
frameConfig: args[0],
scenes: initTable[SceneId, FrameScene](),
currentSceneId: defaultSceneId,
currentSceneId: getFirstSceneId(),
lastRenderAt: 0,
sleepFuture: none(Future[void]),
isRendering: false,
Expand Down
6 changes: 3 additions & 3 deletions frameos/src/scenes/scenes.nim
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import default as defaultScene
import frameos/types
import tables
import tables, options

let defaultSceneId* = "default".SceneId
let defaultSceneId* = some("default".SceneId)

const sceneOptions* = [
("753d9439-8470-4834-8c5d-73264875c5b1".SceneId, "Default Scene"),
]

proc getExportedScenes*(): Table[SceneId, ExportedScene] =
result = initTable[SceneId, ExportedScene]()
result[defaultSceneId] = defaultScene.exportedScene
result["default".SceneId] = defaultScene.exportedScene

# TODO Scene options:
# - start at boot / start when requested
Expand Down
23 changes: 13 additions & 10 deletions frontend/src/scenes/frame/panels/Scenes/SceneDropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function SceneDropDown({ sceneId, context }: SceneDropDownProps) {
const { frameId } = useValues(frameLogic)
const { editScene, editSceneJSON } = useActions(panelsLogic)
const { scenes } = useValues(scenesLogic({ frameId }))
const { toggleSettings, renameScene, duplicateScene, deleteScene, setAsDefault } = useActions(
const { toggleSettings, renameScene, duplicateScene, deleteScene, setAsDefault, removeDefault } = useActions(
scenesLogic({ frameId })
)
const { saveAsTemplate, saveAsZip } = useActions(templatesLogic({ frameId }))
Expand Down Expand Up @@ -79,15 +79,18 @@ export function SceneDropDown({ sceneId, context }: SceneDropDownProps) {
onClick: () => renameScene(scene.id),
icon: <PencilSquareIcon className="w-5 h-5" />,
},
...(!scene.default
? [
{
label: 'Set as default',
onClick: () => setAsDefault(scene.id),
icon: <FlagIcon className="w-5 h-5" />,
},
]
: []),

scene.default
? {
label: 'Remove "start on boot"',
onClick: () => removeDefault(),
icon: <FlagIcon className="w-5 h-5" />,
}
: {
label: 'Set to start on boot',
onClick: () => setAsDefault(scene.id),
icon: <FlagIcon className="w-5 h-5" />,
},
{
label: 'Delete scene',
confirm: 'Are you sure you want to delete this scene?',
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/frame/panels/Scenes/Scenes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export function Scenes() {
</span>
{scene.default ? (
<Tag className="ml-2" color="primary">
default
start on boot
</Tag>
) : null}
{scene?.settings?.refreshInterval && Number.isFinite(scene.settings.refreshInterval) ? (
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/scenes/frame/panels/Scenes/scenesLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const scenesLogic = kea<scenesLogicType>([
actions({
toggleSettings: (sceneId: string) => ({ sceneId }),
setAsDefault: (sceneId: string) => ({ sceneId }),
removeDefault: true,
deleteScene: (sceneId: string) => ({ sceneId }),
renameScene: (sceneId: string) => ({ sceneId }),
duplicateScene: (sceneId: string) => ({ sceneId }),
Expand Down Expand Up @@ -87,6 +88,17 @@ export const scenesLogic = kea<scenesLogicType>([
),
})
},
removeDefault: () => {
frameLogic({ frameId: props.frameId }).actions.setFrameFormValues({
scenes: values.scenes.map((scene) => {
if ('default' in scene) {
const { default: _, ...rest } = scene
return rest
}
return scene
}),
})
},
duplicateScene: ({ sceneId }) => {
const scene = values.scenes.find((s) => s.id === sceneId)
if (!scene) {
Expand Down
Loading