Skip to content

Commit

Permalink
add power on and ...
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Bibby committed Oct 11, 2023
1 parent b27a8a9 commit 938a383
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 48 deletions.
45 changes: 36 additions & 9 deletions ui/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@ import classNames from 'classnames'
import { Fragment, h, render } from 'preact'
import './app.css'
import styles from './app.module.css'
import { sendRemoteCode } from './bravia'
import { getApplicationList, setActiveApp } from './bravia/appControl'
import { avContent, sendRemoteCode, system } from './bravia'
import {
getApplicationList,
getTextForm,
setActiveApp,
} from './bravia/appControl'
import { Buttons } from './components/buttons'
import { DPad } from './components/d-pad'
import { Volume } from './components/volume'
import { usePictureMute, usePowerStatus } from './hooks/use-simple-ip'
import { getPublicKey } from './bravia/encryption'
import { sendText } from './utils/send-text'
import { useCallback } from 'preact/hooks'

h

Expand All @@ -19,7 +26,7 @@ async function openApp(title: string) {
return
}
await setActiveApp({ uri: app.uri })
await sendRemoteCode('Confirm')
// await sendRemoteCode('Confirm')
}

async function openWebApp(url: string) {
Expand All @@ -28,32 +35,52 @@ async function openWebApp(url: string) {
})
}

async function powerOnAndOpenApp(title: string) {
await system.setPowerStatus({ status: true })
await openApp(title)
}
async function powerOnAndSetInput(port: number) {
await system.setPowerStatus({ status: true })
await avContent.setPlayContent({uri:`extInput:hdmi?port=${port}`})
}

function App() {
const [power, setPower] = usePowerStatus()
const [pictureMute, setPictureMute] = usePictureMute()

return (
<Fragment>
<DPad />
<Volume />
<Buttons>
<button onClick={bind('YouTube Music', openApp)}>Music</button>
<button onClick={bind(2, powerOnAndSetInput)}>Switch</button>
<button onClick={bind('Play', sendRemoteCode)}>Play</button>
<button onClick={bind('Back', sendRemoteCode)}>Back</button>

<button onClick={bind('Plex', openApp)}>Plex</button>
<button onClick={bind('Plex', powerOnAndOpenApp)}>Plex</button>
<button onClick={bind('Pause', sendRemoteCode)}>Pause</button>
<button onClick={bind('Home', sendRemoteCode)}>Home</button>

<button
class={classNames({ [styles.powerOff]: !power })}
onClick={bind(!power, setPower)}
>
{/* <button onClick={bind("https://google.com", openWebApp)}>Switch</button>
<div />
<div /> */}

<button onClick={bind(4, powerOnAndSetInput)}>PC</button>
<button onClick={bind(!power, setPower)}>
{power ? 'Power Off' : 'Power On'}
</button>
<button onClick={bind(!pictureMute, setPictureMute)}>
{pictureMute ? 'Screen On' : 'Screen Off'}
</button>

{/* <button>Keyboard</button> */}
</Buttons>
{/* <div>
<form onSubmit={sendText}>
<input type='text' />
<button type='submit'>Send</button>
</form>
</div> */}
{/* <Settings /> */}
</Fragment>
)
Expand Down
24 changes: 24 additions & 0 deletions ui/src/bravia/appControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ export const setActiveApp = braviaAPIFactory<
[options: SetActiveAppOptions],
Application[]
>('appControl', 'setActiveApp', '1.0')

export interface GetTextFormOptions {
encKey: string
}
export interface GetTextFormResult {
text: string
}

/**
* @link https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/appcontrol/v1_1/getTextForm/index.html
*/
export const getTextForm = braviaAPIFactory<
[options: GetTextFormOptions],
GetTextFormResult
>('appControl', 'getTextForm', '1.1')

export interface SetTextFormResult {}
/**
* @link https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/appcontrol/v1_0/setTextForm/index.html
*/
export const setTextForm = braviaAPIFactory<
[message: string],
SetTextFormResult
>('appControl', 'setTextForm', '1.0')
26 changes: 26 additions & 0 deletions ui/src/bravia/avContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { braviaAPIFactory } from './internal'

export interface GetSourceListOptions {
scheme: 'extInput'
}

export interface Source {
source: string
}

export const getSourceList = braviaAPIFactory<[options:GetSourceListOptions], Source[]>(
'avContent',
'getSourceList',
'1.0',
)

export interface SetPlayContentOptions {
uri: string
}


export const setPlayContent = braviaAPIFactory<[options:SetPlayContentOptions], void>(
'avContent',
'setPlayContent',
'1.0',
)
23 changes: 23 additions & 0 deletions ui/src/bravia/encryption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { braviaAPIFactory } from './internal'

export interface GetPublicKeyResult {
publicKey: string
}

export const getPublicKey = braviaAPIFactory<[], GetPublicKeyResult>(
'encryption',
'getPublicKey',
'1.0',
)

export interface GetSecretDataOptions {
encKey: string
}
export interface GetSecretDataResult {
secretData: string
}

export const getSecretData = braviaAPIFactory<
[options: GetSecretDataOptions],
GetSecretDataResult
>('encryption', 'getSecretData', '1.0')
4 changes: 4 additions & 0 deletions ui/src/bravia/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export * as audio from './audio'
export * as system from './system'
export * as appControl from './appControl'
export * as avContent from './avContent'

export { sendRemoteCode } from './ircc-ip'
13 changes: 13 additions & 0 deletions ui/src/bravia/system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { braviaAPIFactory } from './internal'

export interface SetPowerStatusOptions {
status: boolean
}

/**
* @link https://pro-bravia.sony.net/develop/integrate/rest-api/spec/service/system/v1_0/setPowerStatus/index.html
*/
export const setPowerStatus = braviaAPIFactory<
[options: SetPowerStatusOptions],
void
>('system', 'setPowerStatus', '1.0')
2 changes: 1 addition & 1 deletion ui/src/components/d-pad.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function DPad() {
const click = useCallback((c: Click) => {
sendRemoteCode('Confirm')
}, [])
const touch = useMediaQuery('(hover: none) and (pointer: coarse)')
const touch = useMediaQuery('(pointer: coarse)')

const remote = useCallback(
(key: RemoteCommand, e: Event) => {
Expand Down
Empty file added ui/src/components/text.tsx
Empty file.
80 changes: 42 additions & 38 deletions ui/src/components/volume.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,48 @@ import styles from './volume.module.css'
h

async function smartSetVolume(volume: number): Promise<void> {
const targetVolume = Math.floor(volume * 100)
await audio.setAudioVolume({
target: '',
ui: 'on',
volume: String(targetVolume),
})

// const volumeInformation = await audio
// .getVolumeInformation()
// .then(v => v.find(v => v.target === 'speaker'))
// if (volumeInformation === undefined) {
// throw new Error('no volume')
// }

// const maxVolume = volumeInformation.maxVolume
// const currentVolume = volumeInformation.volume
// const targetVolume = Math.floor(volume * maxVolume)

// // await audio.setAudioVolume({
// // target: '',
// // ui: 'on',
// // volume: String(targetVolume),
// // })

// // const newVolumeInformation = await audio
// // .getVolumeInformation()
// // .then(v => v.find(v => v.target === 'speaker'))

// // if (newVolumeInformation?.volume === currentVolume) {
// for (let i = 0; i < Math.abs(currentVolume - targetVolume) * 2; i++) {
// if (currentVolume < targetVolume) {
// await sendRemoteCode('VolumeUp')
// } else {
// await sendRemoteCode('VolumeDown')
// }
// await sleep(300)
// }
// // }
// const targetVolume = Math.floor(volume * 100)
// await audio.setAudioVolume({
// target: '',
// ui: 'on',
// volume: String(targetVolume),
// })
for (let i = 0; i < 10; i++) {
const volumeInformation = await audio
.getVolumeInformation()
.then(v => v.find(v => v.target === 'speaker'))
if (volumeInformation === undefined) {
throw new Error('no volume')
}

const maxVolume = volumeInformation.maxVolume
const currentVolume = volumeInformation.volume
const targetVolume = Math.floor(volume * maxVolume)

if (Math.abs(currentVolume - targetVolume) < 1) {
return
}
// await audio.setAudioVolume({
// target: '',
// ui: 'on',
// volume: String(targetVolume),
// })

// const newVolumeInformation = await audio
// .getVolumeInformation()
// .then(v => v.find(v => v.target === 'speaker'))

// if (newVolumeInformation?.volume === currentVolume) {
for (let i = 0; i < Math.abs(currentVolume - targetVolume) * 2; i++) {
if (currentVolume < targetVolume) {
await sendRemoteCode('VolumeUp')
} else {
await sendRemoteCode('VolumeDown')
}
await sleep(300)
}
// }
}
}

export function Volume() {
Expand Down
61 changes: 61 additions & 0 deletions ui/src/utils/send-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { getTextForm, setTextForm } from '../bravia/appControl'
import { getPublicKey } from '../bravia/encryption'

export async function sendText(text: string): Promise<void> {
const result = await setTextForm(text)
console.log(result)

// const { publicKey } = await getPublicKey()
// const key = await importPublicKey(publicKey)
// const data = await encryptData(text, key)
// getTextForm()
}
function base64ToArrayBuffer(base64: string) {
var binary_string = window.atob(base64)
var len = binary_string.length
var bytes = new Uint8Array(len)
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i)
}
return bytes.buffer
}

function arrayBufferToBase64(buffer: ArrayBuffer) {
var binary = ''
var bytes = new Uint8Array(buffer)
var len = bytes.byteLength
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i])
}
return window.btoa(binary)
}

async function importPublicKey(spki: string) {
const binaryDer = base64ToArrayBuffer(spki)
var cryptoKey = await window.crypto.subtle.importKey(
'spki',
binaryDer,
{
name: 'RSA-OAEP',
modulusLength: 256,
hash: { name: 'sha-256' },
},
false,
['encrypt'],
)
return cryptoKey
}

async function encryptData(message: string, cryptoKey: CryptoKey) {
let enc = new TextEncoder()
let encodedMessage = enc.encode(message)
var encryptedData = await window.crypto.subtle.encrypt(
{
name: 'RSA-OAEP',
},
cryptoKey,
encodedMessage,
)
var encodedData = arrayBufferToBase64(encryptedData)
return encodedData
}

0 comments on commit 938a383

Please sign in to comment.