Skip to content

Commit

Permalink
feat: improved ui and power commands
Browse files Browse the repository at this point in the history
  • Loading branch information
flotwig committed Aug 14, 2020
1 parent f548cf1 commit dba936e
Show file tree
Hide file tree
Showing 14 changed files with 321 additions and 180 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ Lights-out management via Raspberry Pi.
Setup
===

Wiring diagram:
```
Ext. Ethernet
^
| Ext. 5V Power
+---------------------------+ | ^
| Ethernet+-----------+ |
| RasPi 3B+ USB Power In|--------------------+
| (or other) USB Port|----------------+
| USB Port+-------+ | +----------------------------+
+---------------------------+ | +---+USB Port |
| +----|D2 (DATA) Arduino Nano |
+-------------------------------+ | |----|D3 (CLK) (or other) |
| PS/2 Keyboard Port+--------------------|GND (GND) |
| HDMI Out+-------| +----+VIN (5V) |
| Server | || +----------------------------+
| | ||
+-------------------------------+ || +-------------------------------+
|----+USB Plug HDMI Capture Card|
+----+HDMI In |
+-------------------------------+
```

0. Connect everything.
1. Set up an MJPEG streaming server for the USB HDMI capture card.
1. Follow the instructions on the [`uv4l`](http://www.linux-projects.org/uv4l/installation/) website to install the `apt` sources for `uv4l`.
Expand Down
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"start": "parcel watch ./src/index.html"
},
"devDependencies": {
"keycodes-to-ps2-scan-codes": "^1.0.1",
"parcel": "^1.12.4",
"sass": "^1.26.10",
"typescript": "^3.9.7"
}
}
58 changes: 58 additions & 0 deletions frontend/src/controls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import log from './log'
import {
getBreakBytes,
getMakeBytes,
} from 'keycodes-to-ps2-scan-codes'
import { CommandFrame } from 'common'

export function startControls() {
log.info('Connecting to websocket...')
const wsUrl = window.location.href.replace(/^http/, 'ws')
const ws = new WebSocket(wsUrl)

ws.addEventListener('error', (err) => {
log.error('Error connecting to control websocket:', err)
})

ws.addEventListener('close', () => {
log.error('WebSocket closed. Commands can not be sent.')
})

ws.addEventListener('open', () => {
log.info('WebSocket connected.')

const keyEventHandler = KeyEventHandler(ws)

document.addEventListener('keydown', keyEventHandler)
document.addEventListener('keyup', keyEventHandler)

;['Power', 'WakeUp', 'Sleep'].map(code => {
const el = document.querySelector(`button#${code.toLowerCase()}`)
el.addEventListener('mousedown', () => document.dispatchEvent(new KeyboardEvent('keydown', { code })))
el.addEventListener('mouseup', () => document.dispatchEvent(new KeyboardEvent('keyup', { code })))
})
})
}

function KeyEventHandler (ws: WebSocket) {
return function handleKeyEvent (e: KeyboardEvent) {
const getBytes = e.type === 'keyup' ? getBreakBytes : getMakeBytes
let ps2Command

try {
ps2Command = getBytes(e.code)
} catch (err) {
log.warn('Error getting scancode for key', e.code, err)
return
}

const frame: CommandFrame = {
type: 'ps2-command',
ps2Command
}

ws.send(JSON.stringify(frame))

e.preventDefault()
}
}
19 changes: 17 additions & 2 deletions frontend/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,24 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pilo</title>
<link rel="stylesheet" href="./index.scss"/>
</head>
<body>
<img alt="MJPEG stream from server" id="video"/>
<script src="index.ts"></script>
<div id="video-container">
<img alt="MJPEG stream from server" id="video"/>
</div>
<div id="interface">
<div id="logo">
Pilo
<div id="controls">
<button id="power">Power</button>
<button id="sleep">Sleep</button>
<button id="wakeup">WakeUp</button>
</div>
</div>
<ul id="log">
</ul>
</div>
<script src="./index.ts"></script>
</body>
</html>
124 changes: 124 additions & 0 deletions frontend/src/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
$muted: #a9a9a9;
$text: #d5d5d5;
$page-bg: #222222;
$accent: #3b5249;

* {
padding: 0;
margin: 0;
box-sizing: border-box;
}

a, a:visited {
color: darken($text, 10);
}

body, html {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}

body {
display: flex;
flex-direction: row;
// flex-wrap: wrap-reverse;
background: $page-bg;
color: $text;
font-family: sans-serif;
}

#video-container {
min-width: auto;
min-height: auto;
background-color: black;
text-align: center;

#video {
margin: auto;
max-width: 100%;
max-height: 100%;
}
}

#interface {
display: flex;
flex-grow: 1;
flex-direction: column;
min-width: 500px;
min-height: 500px;
padding: 0;
margin: 0;

overflow-y: auto;
overflow-x: hidden;

#logo {
padding: 10px;
font-size: 30px;

#controls {
float: right;

button {
background-color: $accent;
color: $muted;
border-radius: 5px;
padding: 5px;
border: 0;
}

button:hover {
cursor: pointer;
background-color: lighten($accent, 10);
}

button:active {
background-color: darken($accent, 10);
}
}
}

#log {
width: 100%;
overflow-y: auto;
overflow-x: hidden;

li {
padding: 2px 8px;
width: 100%;
list-style-type: none;

.icon {
width: 1em;
display: inline-block;
text-align: center;
}

time {
opacity: .5;
}

&.warn > .icon {
color: yellow;
}

&.error > .icon {
color: red;
}

&.info > .icon {
color: lighten($accent, 50)
}
}

li:nth-child(even) {
background-color: transparentize($color: $accent, $amount: .5);
}

li:nth-child(odd) {
background-color: transparentize($color: $accent, $amount: .8);
}
}
}
56 changes: 9 additions & 47 deletions frontend/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,11 @@
import { keysToScanCodes } from './keys-to-scan-codes'
import { CommandFrame } from 'common'
import { lockKeyboard } from './lock-keyboard'
import { startVideo } from './video'
import { startControls } from './controls'
import { version, repository } from '../../package.json'
import log from './log'

const videoImg = document.querySelector('#video')
log.info(`Welcome to Pilo v${version}! Please report any bugs on the <a href="${repository}">GitHub repo</a>.`)

videoImg.addEventListener('error', (err) => {
console.error('Error connecting to MJPEG stream:', err)
})

videoImg.setAttribute('src', 'video.mjpeg')

const wsUrl = window.location.href.replace(/^http/, 'ws')
const ws = new WebSocket(wsUrl)


const handleKeyEvent = (e) => {
const scanCode = keysToScanCodes[e.code]

if (!scanCode) {
console.warn(`Unmapped keypress: ${e.code}`, { e, keysToScanCodes })
return
}

const ps2Command = [scanCode]

if (e.type === 'keyup') {
ps2Command.unshift(0xF0) // break keypress
}

const frame: CommandFrame = {
type: 'ps2-command',
ps2Command
}

ws.send(JSON.stringify(frame))

e.preventDefault()
}

document.addEventListener('keydown', handleKeyEvent)
document.addEventListener('keyup', handleKeyEvent)

ws.addEventListener('error', (err) => {
console.error('Error connecting to control websocket:', err)
})

ws.addEventListener('open', () => {
console.log('WS connected.')
})
lockKeyboard()
startVideo()
startControls()
Loading

0 comments on commit dba936e

Please sign in to comment.