Dev prototype #1

Merged
david merged 7 commits from dev into main 2025-04-24 11:34:49 -07:00
11 changed files with 73 additions and 53 deletions
Showing only changes of commit 2541bbb081 - Show all commits

View File

@ -10,7 +10,7 @@
},
"scripts": {
"build:scss": "npx sass src/static/css:dist/static/css",
"copy:html": "cp src/static/index.html dist/static",
"copy:html": "cp src/static/*.* dist/static",
"build:js:fe": "npx tsc src/static/js/*.ts --outDir dist/static/js",
"build:js:be": "npx tsc --skipLibCheck src/*.ts --outDir dist",
"build": "npm run build:js:fe && npm run build:js:be && npm run build:scss && npm run copy:html",

View File

@ -10,7 +10,7 @@ import IO from "./io";
private port: number;
private root: string;
public constructor(port: number, root: string, io: IO) {
public constructor(port: number, root: string, test: (device:string)=>void) {
this.port = port;
this.root = root;
this.httpServer = http.createServer((req, res) => {
@ -25,29 +25,16 @@ import IO from "./io";
switch (req.method) {
case "GET":
switch (api) {
case "sensors":
body = JSON.stringify(io.getSensors());
status = 200;
break;
case "signal":
const adapter = parseInt(url.searchParams.get('adapter'));
// body = JSON.stringify(getSignal(adapter));
status = 200;
break;
}
break;
case "PUT":
switch (api) {
case "power":
const channel = decodeURIComponent(query[3]);
const adapter = parseInt(url.searchParams.get('adapter'));
// tune(channel, adapter);
case "test":
const device: string = query[3];
test(device);
status = 202;
break;
}
}
}
else if (req.method === 'GET') {

View File

@ -25,7 +25,7 @@ export default class IO {
heat: boolean;
getMoisture: () => ({ moisture0: number, moisture1: number });
public constructor(LIGHTS_GPIO = 17, HEAT_GPIO=22, DHT_GPIO = 27, DHT_MODEL = 22) {
public constructor(LIGHTS_GPIO = 17, HEAT_GPIO = 22, DHT_GPIO = 27, DHT_MODEL = 22) {
const serial = new Serial()
this.getMoisture = serial.getMoisture.bind(serial);
this.serial = serial;
@ -43,23 +43,18 @@ export default class IO {
dht.setMaxRetries(10);
}
public setPower(state: boolean, GPIO= 17) {
if(GPIO == 17){
public setPower(state: boolean, GPIO = 17) {
if (GPIO == 17) {
this.lights = state;
this.gpioLights.digitalWrite(this.lights ? ON : OFF);
}
else if(GPIO == 22){
else if (GPIO == 22) {
this.heat = state;
this.gpioHeat.digitalWrite(this.heat ? ON : OFF);
}
}
// public togglePower() {
// this.power = !this.power;
// this.gpio.digitalWrite(this.power ? ON : OFF);
// }
private round = (n) =>
(n * 100) / 100

7
src/programs.json Normal file
View File

@ -0,0 +1,7 @@
[
{
"name": "tomato",
"daylightHours": 16,
"soilMoisture": 75
}
]

View File

@ -1,17 +1,55 @@
import HttpServer from './http';
import IO, { ISensors } from './io';
import VideoSocket from './ws';
import * as programs from './programs.json'
const HTTP_PORT = process.env.HTTP_PORT ? parseInt(process.env.HTTP_PORT, 10) : 8080;
const WS_PORT = process.env.WS_PORT ? parseInt(process.env.WS_PORT, 10) : 3003;
const STATIC_ROOT = process.cwd() + "/dist/static";
const TV_DEV_0 = process.env.TV_DEV_0 ?? '/dev/video0'
const GPIO_LIGHTS = parseInt(process.env.GPIO_LIGHTS) ?? 17;
const GPIO_HEAT = parseInt(process.env.GPIO_HEAT) ?? 22;
const START_HOUR = parseInt(process.env.START_HOUR) ?? 8;
interface IProgram {
name:string,
daylightHours: number,
soilMoisture: number
}
const io = new IO();
const getSensors: ()=>ISensors = io.getSensors.bind(io);
const getSensors: () => ISensors = io.getSensors.bind(io);
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, io);
const test = (device: string) => {
const gpio = device == "lights" ? GPIO_LIGHTS : device == "heat" ? GPIO_HEAT : NaN
if (!isNaN(gpio)) {
const state = io[device];
io.setPower(!state, gpio)
setTimeout(() => {
io.setPower(state, gpio)
}, 4000)
}
}
const runProgram = async (ID = 0) =>{
let state = false;
const program: IProgram = programs[ID];
const {daylightHours, soilMoisture} = program;
const now = new Date();
const startTime = new Date();
startTime.setHours(START_HOUR, 0, 0, 0);
const endTime = new Date(startTime.getTime());
endTime.setHours(startTime.getHours() + daylightHours);
if(now >= startTime && now <= endTime){
state = true;
}
io.setPower(state,GPIO_LIGHTS);
io.setPower(state,GPIO_HEAT);
}
runProgram();
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, test);
const videoSocket = new VideoSocket(WS_PORT, TV_DEV_0, getSensors);
httpServer.start();
@ -26,31 +64,28 @@ process.stdin.on("data", async (data: string) => {
const input = data.trim();
console.log(`Received: "${input}"`);
const val = parseInt(input);
switch(val) {
switch (val) {
case 0:
break;
case 1:
io.setPower(false,17);
io.setPower(false, GPIO_LIGHTS);
break;
case 2:
io.setPower(true,17);
io.setPower(true, GPIO_LIGHTS);
break;
case 3:
io.setPower(false,22);
io.setPower(false, GPIO_HEAT);
break;
case 4:
io.setPower(true,22);
io.setPower(true, GPIO_HEAT);
break;
case 5:
console.log("a ", getSensors())
console.log(getSensors())
break;
default:
console.log("No option for "+input)
console.log("No option for " + input)
}
});

BIN
src/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>WebRTC Stream</title>
<title>Grow</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="css/styles.css" />
@ -21,6 +21,7 @@
<p id="temperature"></p>
<p id="humidity"></p> -->
</div>
<div><button onclick="test('lights')">Test Lights</button> <button onclick="test('heat')">Test Heat</button></div>
</main>
</div>

View File

@ -1,9 +1,4 @@
const getSensors = () =>{
const test = (gpio: string ) => {
fetch(`/api/test/${gpio}`, { method: "PUT"})
};
}
const poll = () =>{
fetch("/api/sensors").then(r=>r.json()).then(data =>{
console.log("data ",data)
})
}

View File

@ -51,7 +51,7 @@ export default class VideoSocket {
};
dataChannel.onmessage = (event) => {
console.log("📦 Server received message:", event.data);
// console.log("📦 Server received message:", event.data);
};
dataChannel.onclose = () => {

View File

@ -44,7 +44,7 @@
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "noUncheckedSideEffectImports": true, /* Check side effect imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
"resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
@ -106,7 +106,7 @@
"skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": ["src"],
"include": ["src/**/*.ts"],
"exclude": [
"node_modules","./node_modules/@roamhq/wrtc"
]