Dev prototype #1
@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:scss": "npx sass src/static/css:dist/static/css",
|
"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:fe": "npx tsc src/static/js/*.ts --outDir dist/static/js",
|
||||||
"build:js:be": "npx tsc --skipLibCheck src/*.ts --outDir dist",
|
"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",
|
"build": "npm run build:js:fe && npm run build:js:be && npm run build:scss && npm run copy:html",
|
||||||
|
21
src/http.ts
21
src/http.ts
@ -10,7 +10,7 @@ import IO from "./io";
|
|||||||
private port: number;
|
private port: number;
|
||||||
private root: string;
|
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.port = port;
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.httpServer = http.createServer((req, res) => {
|
this.httpServer = http.createServer((req, res) => {
|
||||||
@ -25,29 +25,16 @@ import IO from "./io";
|
|||||||
switch (req.method) {
|
switch (req.method) {
|
||||||
case "GET":
|
case "GET":
|
||||||
switch (api) {
|
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;
|
break;
|
||||||
case "PUT":
|
case "PUT":
|
||||||
switch (api) {
|
switch (api) {
|
||||||
case "power":
|
case "test":
|
||||||
const channel = decodeURIComponent(query[3]);
|
const device: string = query[3];
|
||||||
const adapter = parseInt(url.searchParams.get('adapter'));
|
test(device);
|
||||||
// tune(channel, adapter);
|
|
||||||
status = 202;
|
status = 202;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (req.method === 'GET') {
|
else if (req.method === 'GET') {
|
||||||
|
15
src/io.ts
15
src/io.ts
@ -17,7 +17,7 @@ export interface ISensors {
|
|||||||
humidity: number;
|
humidity: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class IO {
|
export default class IO {
|
||||||
gpioLights: pigpio.Gpio
|
gpioLights: pigpio.Gpio
|
||||||
gpioHeat: pigpio.Gpio
|
gpioHeat: pigpio.Gpio
|
||||||
serial: Serial;
|
serial: Serial;
|
||||||
@ -25,7 +25,7 @@ export default class IO {
|
|||||||
heat: boolean;
|
heat: boolean;
|
||||||
getMoisture: () => ({ moisture0: number, moisture1: number });
|
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()
|
const serial = new Serial()
|
||||||
this.getMoisture = serial.getMoisture.bind(serial);
|
this.getMoisture = serial.getMoisture.bind(serial);
|
||||||
this.serial = serial;
|
this.serial = serial;
|
||||||
@ -43,23 +43,18 @@ export default class IO {
|
|||||||
dht.setMaxRetries(10);
|
dht.setMaxRetries(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPower(state: boolean, GPIO= 17) {
|
public setPower(state: boolean, GPIO = 17) {
|
||||||
if(GPIO == 17){
|
if (GPIO == 17) {
|
||||||
this.lights = state;
|
this.lights = state;
|
||||||
this.gpioLights.digitalWrite(this.lights ? ON : OFF);
|
this.gpioLights.digitalWrite(this.lights ? ON : OFF);
|
||||||
}
|
}
|
||||||
else if(GPIO == 22){
|
else if (GPIO == 22) {
|
||||||
this.heat = state;
|
this.heat = state;
|
||||||
this.gpioHeat.digitalWrite(this.heat ? ON : OFF);
|
this.gpioHeat.digitalWrite(this.heat ? ON : OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// public togglePower() {
|
|
||||||
// this.power = !this.power;
|
|
||||||
// this.gpio.digitalWrite(this.power ? ON : OFF);
|
|
||||||
// }
|
|
||||||
|
|
||||||
private round = (n) =>
|
private round = (n) =>
|
||||||
(n * 100) / 100
|
(n * 100) / 100
|
||||||
|
|
||||||
|
7
src/programs.json
Normal file
7
src/programs.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "tomato",
|
||||||
|
"daylightHours": 16,
|
||||||
|
"soilMoisture": 75
|
||||||
|
}
|
||||||
|
]
|
@ -1,17 +1,55 @@
|
|||||||
import HttpServer from './http';
|
import HttpServer from './http';
|
||||||
import IO, { ISensors } from './io';
|
import IO, { ISensors } from './io';
|
||||||
import VideoSocket from './ws';
|
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 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 WS_PORT = process.env.WS_PORT ? parseInt(process.env.WS_PORT, 10) : 3003;
|
||||||
const STATIC_ROOT = process.cwd() + "/dist/static";
|
const STATIC_ROOT = process.cwd() + "/dist/static";
|
||||||
const TV_DEV_0 = process.env.TV_DEV_0 ?? '/dev/video0'
|
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 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);
|
const videoSocket = new VideoSocket(WS_PORT, TV_DEV_0, getSensors);
|
||||||
|
|
||||||
httpServer.start();
|
httpServer.start();
|
||||||
@ -26,31 +64,28 @@ process.stdin.on("data", async (data: string) => {
|
|||||||
const input = data.trim();
|
const input = data.trim();
|
||||||
console.log(`Received: "${input}"`);
|
console.log(`Received: "${input}"`);
|
||||||
const val = parseInt(input);
|
const val = parseInt(input);
|
||||||
switch(val) {
|
switch (val) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
io.setPower(false,17);
|
io.setPower(false, GPIO_LIGHTS);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
io.setPower(true,17);
|
io.setPower(true, GPIO_LIGHTS);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
io.setPower(false,22);
|
io.setPower(false, GPIO_HEAT);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
io.setPower(true,22);
|
io.setPower(true, GPIO_HEAT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
console.log("a ", getSensors())
|
console.log(getSensors())
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("No option for "+input)
|
console.log("No option for " + input)
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
BIN
src/static/favicon.ico
Normal file
BIN
src/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 318 B |
@ -2,7 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>WebRTC Stream</title>
|
<title>Grow</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="stylesheet" href="css/styles.css" />
|
<link rel="stylesheet" href="css/styles.css" />
|
||||||
@ -21,6 +21,7 @@
|
|||||||
<p id="temperature"></p>
|
<p id="temperature"></p>
|
||||||
<p id="humidity"></p> -->
|
<p id="humidity"></p> -->
|
||||||
</div>
|
</div>
|
||||||
|
<div><button onclick="test('lights')">Test Lights</button> <button onclick="test('heat')">Test Heat</button></div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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)
|
|
||||||
})
|
|
||||||
}
|
|
@ -51,7 +51,7 @@ export default class VideoSocket {
|
|||||||
};
|
};
|
||||||
|
|
||||||
dataChannel.onmessage = (event) => {
|
dataChannel.onmessage = (event) => {
|
||||||
console.log("📦 Server received message:", event.data);
|
// console.log("📦 Server received message:", event.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
dataChannel.onclose = () => {
|
dataChannel.onclose = () => {
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
// "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. */
|
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||||
// "noUncheckedSideEffectImports": true, /* Check side effect 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. */
|
// "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. */
|
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||||
/* JavaScript Support */
|
/* JavaScript Support */
|
||||||
@ -106,7 +106,7 @@
|
|||||||
"skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
"skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
},
|
},
|
||||||
"include": ["src"],
|
"include": ["src/**/*.ts"],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules","./node_modules/@roamhq/wrtc"
|
"node_modules","./node_modules/@roamhq/wrtc"
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user