From 869e1e574cf1610674b0602d30915b0edf59224c Mon Sep 17 00:00:00 2001 From: Boaz Sender Date: Mon, 31 Mar 2025 10:04:57 -0700 Subject: [PATCH] stable lcd scrolling --- build/screen.js | 51 ++++++++++++++++++++++++++-------- docs/readme.md | 9 ++++-- package.json | 2 +- screen.ts | 74 +++++++++++++++++++++++++++++++++++++------------ tsconfig.json | 4 +++ 5 files changed, 108 insertions(+), 32 deletions(-) diff --git a/build/screen.js b/build/screen.js index ad29090..f32432f 100644 --- a/build/screen.js +++ b/build/screen.js @@ -1,23 +1,52 @@ import { PrismaClient } from "@prisma/client"; const prisma = new PrismaClient(); import LCD from "raspberrypi-liquid-crystal"; +const timer = (ms) => new Promise((res) => setTimeout(res, ms)); const lcd = new LCD(1, 0x27, 16, 2); +const tag = " Black Portal 1234 E Davison, Detroit Michigan"; lcd.beginSync(); lcd.clearSync(); -lcd.printSync('Black'); -lcd.setCursorSync(0, 1); -lcd.printSync('Portal'); -setInterval(async () => { +let tagCount = 0; +setInterval(() => { + lcd.printLineSync(1, " "); + setTimeout(() => { + lcd.printLineSync(1, tag.substring(tagCount, 16 + tagCount)); + }, 50); + tagCount++; + if (tagCount > tag.length) { + tagCount = 0; + } +}, 500); +const getStanza = async () => { const stanzaCount = await prisma.stanza.count(); const skip = Math.floor(Math.random() * stanzaCount); const randomStanza = await prisma.stanza.findMany({ - take: 1, skip: skip, + take: 1, }); - if (randomStanza) { - lcd.clearSync(); - lcd.printSync(randomStanza[0].text.substring(0, 16)); - lcd.setCursorSync(0, 1); - lcd.printSync(randomStanza[0].text.substring(16, 32)); + return randomStanza[0].text; +}; +let stanza = await getStanza(); +while (true) { + let outerInterval; + let innerInterval; + if (stanza) { + let characterLocation = 0; + outerInterval = setInterval(async () => { + lcd.printLineSync(0, " "); + innerInterval = setTimeout(() => { + lcd.printLineSync(0, `${16 - characterLocation > 0 + ? Array(16 - characterLocation).join(" ") + : ""}${stanza}`.substring(characterLocation, 16 + characterLocation)); + }, 50); + characterLocation++; + if (characterLocation > stanza.length) { + stanza = await getStanza(); + characterLocation = 0; + } + }, 700); } -}, 3000); + await timer((16 + stanza.length) * 750); + clearInterval(outerInterval); + clearInterval(innerInterval); +} diff --git a/docs/readme.md b/docs/readme.md index 1e82707..b582916 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,21 +1,26 @@ -# Internet radio electronics for Black Portal Detroit +# Internet radio electronics and software for Black Portal Detroit + Electronics and software for the Black Portal Detroit work By Wes Taylor for the [Code Switch show at at MOCAD](https://thekitchen.org/on-view/code-switch-distributing-blackness-reprogramming-internet-art/). Electronics and software built and written by Boaz Sender based on Wes' concept and at Wes' direction. ## Software provisioning and setup -This repository also contains documentation for how to buy and setup the electronics for Black Portal Detroit. + +This repository also contains documentation for how to buy and setup the electronics for Black Portal Detroit. 1. Broadcaster bill of materials and software setup instructions in [broadcaster.md](broadcaster.md) 2. Listener bill of materials and software setup instructions in [listener.md](listener.md) ## Custom software + This repository contains custom software for turning a m3u radio stream into a logic for random selection of lyrics from an sqlite database of song stanzas written by Detroiters from the neighborhood where MOCAD is. 3. Custom software development instructions in [listener-lcd-screen-software.md](listener-lcd-screen-software.md) ## Turning on the devices + 4. The sequence for turning on the system is in [how-to-turn-it-on.md](how-to-turn-it-on.md) Prior research that didn't work in `research-` md files. ## Live access + 5. If everything is turned on and configured properly, you may visit https://blackportaldetroit.com to hear the broadcaster. diff --git a/package.json b/package.json index 6628d6f..c0efd48 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "https://blackportaldetroit.com", "main": "index.js", "scripts": { - "build": "tsc screen.ts", + "build": "tsc", "deploy": "npm run build && rsync -avx rsync -a --exclude-from='exclude.txt' ./ grace@listener.local:portal" }, "repository": { diff --git a/screen.ts b/screen.ts index adb094a..1793a3c 100644 --- a/screen.ts +++ b/screen.ts @@ -1,31 +1,69 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient, Stanza } from "@prisma/client"; const prisma = new PrismaClient(); -import LCD from "raspberrypi-liquid-crystal" -const lcd = new LCD( 1, 0x27, 16, 2 ); +import LCD from "raspberrypi-liquid-crystal"; +const timer = (ms: number) => new Promise((res) => setTimeout(res, ms)); + +const lcd = new LCD(1, 0x27, 16, 2); +const tag = " Black Portal 1234 E Davison, Detroit Michigan"; lcd.beginSync(); lcd.clearSync(); -lcd.printSync( 'Black' ); -lcd.setCursorSync(0, 1); -lcd.printSync( 'Portal' ); +let tagCount = 0; -setInterval(async ()=>{ +setInterval(() => { + lcd.printLineSync(1, " "); + setTimeout(() => { + lcd.printLineSync(1, tag.substring(tagCount, 16 + tagCount)); + }, 50); + + tagCount++; + + if (tagCount > tag.length) { + tagCount = 0; + } +}, 500); + +const getStanza = async () => { const stanzaCount = await prisma.stanza.count(); - const skip = Math.floor(Math.random() * stanzaCount) - 1; + const skip = Math.floor(Math.random() * stanzaCount); const randomStanza = await prisma.stanza.findMany({ - take: 2, skip: skip, + take: 1, }); - if(randomStanza){ - lcd.clearSync(); - if(randomStanza[0].text.length < 16){ - lcd.printSync( randomStanza[0].text ); - lcd.setCursorSync(0, 1); - lcd.printSync( randomStanza[1].text ); - } - } -}, 3000) + return randomStanza[0].text as string; +}; +let stanza = await getStanza(); + +while (true) { + let outerInterval; + let innerInterval; + if (stanza) { + let characterLocation = 0; + outerInterval = setInterval(async () => { + lcd.printLineSync(0, " "); + innerInterval = setTimeout(() => { + lcd.printLineSync( + 0, + `${ + 16 - characterLocation > 0 + ? Array(16 - characterLocation).join(" ") + : "" + }${stanza}`.substring(characterLocation, 16 + characterLocation) + ); + }, 50); + characterLocation++; + + if (characterLocation > stanza.length) { + stanza = await getStanza(); + characterLocation = 0; + } + }, 700); + } + await timer((16 + stanza.length) * 750); + clearInterval(outerInterval); + clearInterval(innerInterval); +} diff --git a/tsconfig.json b/tsconfig.json index 3aeaf76..6a06006 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,8 @@ { + "exclude": [ + "node_modules", + "prisma" + ], "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */