import Remote from 'node-upnp-remote' ; import UPNP from 'node-upnp' ; import { Samsung , KEYS , APPS } from 'samsung-tv-control' ; import HJSamsungTv from 'samsung-remote-pin-paired' ; import { PLATFORM_NAME , PLUGIN_NAME } from '../settings' ; import parseSerialNumber from './parseSerialNumber' ; import { Logger } from 'homebridge' ; import { DeviceConfig } from '../types/deviceConfig' ; import wait from './wait' ; import { decodeIdentity } from './identity' ; import chalk from 'chalk' ; import hasCapability from './hasCapability' ; const getRemoteConfig = ( config ) => { const model = parseSerialNumber ( config . modelName ) ; const { year = 2013 } = model || { } ; const supportsLegacy = typeof year === `number` && year < 2014 ; const port = config . remoteControlPort || supportsLegacy ? 55000 : 8002 ; return { mac : config . mac , ip : config . lastKnownIp , name : PLATFORM_NAME , token : config . token , port , } ; } ; /**
 * Checks if the token is supposed to be used with the H/J-Series library
 * and returns the
 */ const getIdentity = ( config ) => { const { token } = config ; if ( ! token ) { return null ; } try { const identity = decodeIdentity ( token ) ; if ( identity . sessionId && identity . aesKey ) { return identity ; } } catch ( err ) { } return null ; } ; export const getPairing = async ( config , log ) => { const { token , modelName } = config ; if ( token ) { return token ; } const model = parseSerialNumber ( modelName ) ; const { year = 2013 } = model || { } ; const supportsLegacy = typeof year === `number` && year < 2014 ; if ( supportsLegacy ) { log . debug ( `${ config . name } - This TV probably won't need to be paired since it is from ${ year } and should support the legacy protocol.` + chalk `If you can't control it you still can try pairing it however with {blue npx ${ PLUGIN_NAME } pair2 ${ config . lastKnownIp } ${ config . mac }}` ) ; return null ; } const { yearKey } = model || { } ; if ( yearKey === `J` || yearKey === `H` ) { log . info ( `${ config . name } - This TV seems to be a ${ yearKey }-Series.` + chalk `Please run {blue npx ${ PLUGIN_NAME } pair1 ${ config . lastKnownIp } ${ config . mac }} to get a pairing token.` ) ; } else { log . info ( chalk `${ config . name } - Please run {blue npx ${ PLUGIN_NAME } pair2 ${ config . lastKnownIp } ${ config . mac }} or` + chalk `{blue npx ${ PLUGIN_NAME } pair1 ${ config . lastKnownIp } ${ config . mac }} to get a pairing token.` ) ; } return null ; } ; const sendKey = async ( config , key ) => { const identity = getIdentity ( config ) ; if ( identity ) { const tv = new HJSamsungTv ( { ip : config . lastKnownIp , appId : `721b6fce-4ee6-48ba-8045-955a539edadb` , userId : `654321` , } ) ; await tv . init ( identity ) ; const connection = await tv . connect ( ) ; await tv . sendKey ( key ) ; await connection . close ( ) ; return ; } const cfg = getRemoteConfig ( config ) ; const control = new Samsung ( cfg ) ; await control . sendKeyPromise ( key ) ; control . closeConnection ( ) ; } ; export const sendKeys = async ( config , keys ) => { const identity = getIdentity ( config ) ; if ( identity ) { const tv = new HJSamsungTv ( { ip : config . lastKnownIp , appId : `721b6fce-4ee6-48ba-8045-955a539edadb` , userId : `654321` , } ) ; await tv . init ( identity ) ; const connection = await tv . connect ( ) ; for ( let i = 0 ; i < keys . length ; ++ i ) { const key = keys [ i ] ; await tv . sendKey ( key ) ; await wait ( config . delay ) ; } await connection . close ( ) ; return ; } const cfg = getRemoteConfig ( config ) ; const control = new Samsung ( cfg ) ; for ( let i = 0 ; i < keys . length ; ++ i ) { const key = keys [ i ] ; await control . sendKeyPromise ( key ) ; await wait ( config . delay ) ; } control . closeConnection ( ) ; } ; export const openApp = async ( config , app ) => { const identity = getIdentity ( config ) ; if ( identity ) { return ; } const cfg = getRemoteConfig ( config ) ; const control = new Samsung ( cfg ) ; await control . openAppPromise ( app ) ; control . closeConnection ( ) ; } ; const turnOn = async ( config ) => { const cfg = getRemoteConfig ( config ) ; const control = new Samsung ( cfg ) ; await control . turnOn ( ) ; control . closeConnection ( ) ; } ; export const getActive = async ( config ) => { const cfg = getRemoteConfig ( config ) ; const control = new Samsung ( cfg ) ; let available = false ; try { available = await control . isAvailablePing ( ) ; control . closeConnection ( ) ; } catch ( err ) { } return available ; } ; export const setActive = async ( config , active ) => { const isActive = await getActive ( config ) ; if ( active === isActive ) { return ; } if ( active ) { await turnOn ( config ) ; } else { const identity = getIdentity ( config ) ; const key = identity ? KEYS . KEY_POWER : KEYS . KEY_POWEROFF ; sendKey ( config , key ) ; } } ; export const getVolume = async ( config ) => { const { lastKnownLocation : url } = config ; const remote = new Remote ( { url } ) ; const volume = await remote . getVolume ( ) ; return volume ; } ; export const setVolume = async ( config , volume ) => { const { lastKnownLocation : url , disableUpnpSetters } = config ; if ( ! disableUpnpSetters && hasCapability ( config , `SetVolume` ) ) { const remote = new Remote ( { url } ) ; await remote . setVolume ( volume ) ; return ; } const currentVolume = await getVolume ( config ) ; const volumeOffset = volume - currentVolume ; if ( volumeOffset === 0 ) { return ; } const keys = [ ] ; let key = KEYS . KEY_VOLUP ; if ( volumeOffset < 0 ) { key = KEYS . KEY_VOLDOWN ; } for ( let i = 0 ; i < Math . abs ( volumeOffset ) ; ++ i ) { keys . push ( key ) ; } await sendKeys ( config , keys ) ; } ; export const volumeUp = async ( config ) => { await sendKey ( config , KEYS . KEY_VOLUP ) ; } ; export const volumeDown = async ( config ) => { await sendKey ( config , KEYS . KEY_VOLDOWN ) ; } ; export const getMute = async ( config ) => { const { lastKnownLocation : url } = config ; const remote = new Remote ( { url } ) ; return remote . getMute ( ) ; } ; export const setMute = async ( config , mute ) => { const { lastKnownLocation : url , disableUpnpSetters } = config ; if ( ! disableUpnpSetters && hasCapability ( config , `SetMute` ) ) { const remote = new Remote ( { url } ) ; await remote . setMute ( mute ) ; return ; } if ( hasCapability ( config , `GetMute` ) ) { const isMuted = await getMute ( config ) ; if ( ( isMuted && mute ) || ( ! isMuted && ! mute ) ) { return ; } } await sendKey ( config , KEYS . KEY_MUTE ) ; } ; export const getBrightness = async ( config ) => { const { lastKnownLocation : url } = config ; const upnp = new UPNP ( { url } ) ; const { CurrentBrightness : brightness } = await upnp . call ( `RenderingControl` , `GetBrightness` , { InstanceID : 0 } ) ; return brightness ; } ; export const setBrightness = async ( config , brightness ) => { const { lastKnownLocation : url , disableUpnpSetters } = config ; if ( ! disableUpnpSetters ) { const upnp = new UPNP ( { url } ) ; await upnp . call ( `urn:upnp-org:serviceId:RenderingControl` , `SetBrightness` , { InstanceID : 0 , DesiredBrightness : brightness } ) ; } } ; export const rewind = async ( config ) => { await sendKey ( config , KEYS . KEY_REWIND ) ; } ; export const fastForward = async ( config ) => { await sendKey ( config , KEYS . KEY_FF ) ; } ; export const arrowUp = async ( config ) => { await sendKey ( config , KEYS . KEY_UP ) ; } ; export const arrowDown = async ( config ) => { await sendKey ( config , KEYS . KEY_DOWN ) ; } ; export const arrowLeft = async ( config ) => { await sendKey ( config , KEYS . KEY_LEFT ) ; } ; export const arrowRight = async ( config ) => { await sendKey ( config , KEYS . KEY_RIGHT ) ; } ; export const select = async ( config ) => { await sendKey ( config , KEYS . KEY_ENTER ) ; } ; export const back = async ( config ) => { await sendKey ( config , KEYS . KEY_RETURN ) ; } ; export const exit = async ( config ) => { await sendKey ( config , KEYS . KEY_HOME ) ; } ; export const playPause = async ( config ) => { await sendKey ( config , KEYS . KEY_PLAY ) ; } ; export const info = async ( config ) => { await sendKey ( config , KEYS . KEY_INFO ) ; } ; export const openTV = async ( config ) => { await sendKey ( config , KEYS . KEY_TV ) ; } ; export const openHDMI = async ( config ) => { await sendKey ( config , KEYS . KEY_HDMI ) ; } ; export const openHDMI1 = async ( config ) => { await sendKey ( config , KEYS . KEY_HDMI1 ) ; } ; export const openHDMI2 = async ( config ) => { await sendKey ( config , KEYS . KEY_HDMI2 ) ; } ; export const openHDMI3 = async ( config ) => { await sendKey ( config , KEYS . KEY_HDMI3 ) ; } ; export const openHDMI4 = async ( config ) => { await sendKey ( config , KEYS . KEY_HDMI4 ) ; } ;