This repository has been archived by the owner on Feb 3, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(device): add UI to control device state
- Loading branch information
1 parent
ea3126a
commit 7d89ebf
Showing
3 changed files
with
183 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Device UI</title> | ||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> | ||
<style type="text/css"> | ||
main { | ||
max-width: 960px; | ||
margin: 0 auto; | ||
} | ||
</style> | ||
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> | ||
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> | ||
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="text/babel"> | ||
|
||
const Main = ({ children }) => <main> | ||
<h1>Control device</h1> | ||
{children} | ||
</main> | ||
|
||
const TempSlider = () => { | ||
const [temp, setTemp] = React.useState(0) | ||
return <div className="form-group"> | ||
<label htmlFor="temperatureSlider">Temperature: {temp}</label> | ||
<input | ||
type="range" | ||
className="form-control-range" | ||
id="temperatureSlider" | ||
min="-30" | ||
max="30" | ||
value={temp} | ||
onChange={({ target: { value } }) => { | ||
setTemp(parseInt(value, 10)) | ||
}} | ||
onMouseUp={() => { | ||
fetch('/update', { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
temp: { | ||
v: temp, | ||
ts: new Date().toISOString(), | ||
}, | ||
}), | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}) | ||
}} | ||
/> | ||
</div> | ||
} | ||
|
||
ReactDOM.render( | ||
<Main> | ||
<form> | ||
<TempSlider/> | ||
</form> | ||
</Main>, | ||
document.getElementById('root'), | ||
) | ||
|
||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import * as path from 'path' | ||
import * as http from 'http' | ||
import { promises as fs } from 'fs' | ||
import chalk from 'chalk' | ||
|
||
export const uiServer = async (args: { | ||
onUpdate: (update: object) => void | ||
}) => { | ||
const port = 1024 + Math.round(Math.random() * (65535 - 1024)) | ||
const uiPage = await fs.readFile( | ||
path.resolve(process.cwd(), 'data', 'device-ui.html'), | ||
'utf-8', | ||
) | ||
|
||
const requestHandler: http.RequestListener = async (request, response) => { | ||
let body = '' | ||
switch (request.url) { | ||
case '/': | ||
case '/index.html': | ||
response.writeHead(200, { | ||
'Content-Length': Buffer.byteLength(uiPage), | ||
'Content-Type': 'text/html', | ||
}) | ||
response.end(uiPage) | ||
break | ||
case '/update': | ||
request.on('data', chunk => { | ||
body += chunk.toString() // convert Buffer to string | ||
}) | ||
request.on('end', () => { | ||
try { | ||
const update = JSON.parse(body) | ||
args.onUpdate(update) | ||
response.statusCode = 202 | ||
response.end() | ||
} catch (err) { | ||
console.log(err) | ||
const errData = JSON.stringify(err) | ||
response.writeHead(400, { | ||
'Content-Length': Buffer.byteLength(errData), | ||
'Content-Type': 'application/json', | ||
}) | ||
response.end(errData) | ||
} | ||
}) | ||
break | ||
default: | ||
response.statusCode = 404 | ||
response.end() | ||
} | ||
} | ||
|
||
const server = http.createServer(requestHandler) | ||
|
||
server.listen(port, () => { | ||
console.log( | ||
chalk.green( | ||
`To control this device open your browser on http://localhost:${port}`, | ||
), | ||
) | ||
}) | ||
} |