hannemann / BLE-Remote-Companion

Control an NVIDIA Shield or other Android TV Devices or any other device that can utilize a bluetooth keyboard
3 stars 0 forks source link

Bluetooth LE Remote Companion

Remotely control devices via Bluetooth using an IR remote, from a Browser, Homeassistant or Node-RED.
(IR is available if a TSOP is soldered to PIN 23)

Features

This software turns an ESP32 into a virtual keyboard and mouse running a websocket server and/or Home Assistant websocket API client.

The built in webserver offers a HTML page with a grapical remote, a simple keyboard and mouse functionality. All available buttons can be customized to send a keycode of your choice.

Button presses sent by an IR remote can also be broadcasted to Home Assistant or all connected websocket clients making it possible to start your favourite streaming app via adb or toggle lights or...
The graphical remote frontend offers the F1-F12 buttons which AFAIK do nothing on Android TV devices but are especially useful in conjunction with apps like Key Mapper. E.g.: map F1 in Key Mapper to open Kodi than map F1 to a button on your remote and you are done! No Home Assistant ADB involved.

The web frontend offers an easy, self-explanatory way to configure your IR remote. It is also possible to change the default keycode that is sent by a button.

An easy to print housing for a d1 mini style esp32 can be found in the case/D1-Mini subfolder.

Supported Hardware

(Strongly) Recommended Peripherals

Supported Browsers (recent versions only)

Installation

PlatformIO

Configuration

WIFI

Connect to the WIFI BLERC with the password 0987654321, point your browser to 192.168.4.1 and enter your WIFI Credentials. Device reboots and than connects to the WIFI. Look up the IP in the router and than point a browser to it.

Bluetooth

Bind the device to control to BLE Remote Companion.
It happend to me sometinmes that the mouse did not work instantly. A rebind always helped in that cases.

Other

You find a configuration page in the menu of the frontend. Config Description
General
Room Give it a name (recommended to be able to differentiate between several devices when events are evaluated by HA)
IR
Ignore unknown protocol Ignore IR signals that use an unknown protocol
Keyboard
Layout Match the layout to the layout of the device
Home Assistant API
Enable Enable HA API support
IP IP Address of machine running Home Assistant
Port Home Assistant frontend port (8123)
Token Long lived API Token
Send assigned IR Codes Send IR Button presses that are already assigned to a keypress also
Websocket Broadcasts
Enable Enable Websocket broadcast messages
Send assigned IR Codes Send IR Button presses that are already assigned to a keypress also

Navigation

Main Menu

Home Assistant

BLE Remote Companion utilizes the Home Assistant Websocket API if enabled. Simply add the IP address, port and a Long-lived access token to be prepared.

The client calls the script ble_rc_to_ha if a button on a remote or in the frontend is pressed. The parameters for the script contain all information needed to invoke an arbitrary action within your Home Assistant. I prefer a simple script that once invoked fires an event to trigger automations. Using it this way enables you to create automations like you would normally do for any other trigger. If the pressed button has an ir code assigned the message is omitted unless 'Send assigned IR codes' is enabled in the configuration.

Parameters sent

Script ble_rc_to_ha called by your Remote Companion

ble_rc_to_ha:
  fields:
    method:
      description: "Keydown or up"
      example: "keydown"
      required: true
    ir_protocol:
      description: "The ir protocol id"
      example: "1"
      required: true
    ir_code:
      description: "The ir code"
      example: "131578875"
      required: true
    type:
      description: "The keyboard type"
      example: "KEYBOARD"
      required: true
    code:
      description: "The key code"
      example: "KEYBOARD_ENTER"
      required: true
    room:
      description: "The ble-rc device room"
      example: "Living"
      required: true
    longpress:
      description: "Pressed for longer than 500ms"
      example: "true"
      required: true
  sequence:
    - event: ble_rc_to_ha
      event_data:
        method: "{{ method }}"
        ir_protocol: "{{ ir_protocol }}"
        ir_code: "{{ ir_code }}"
        type: "{{ type }}"
        code: "{{ code }}"
        room: "{{ room }}"
        longpress: "{{ longpress }}"

An automation that gets triggered by this event could look like this:

- id: "91243432-708f-11ec-bf72-93a5ed09c06e"
  alias: Do Something
  trigger:
    - platform: event
      event_type:
        - ble_rc_to_ha
  condition: >
    {{
      trigger.event.data.room == 'Living' and 
      trigger.event.data.method == 'keyup' and
      trigger.event.data.protocol == 3 and
      trigger.event.data.code == 45957311
    }}
  action:
    service: script.do_something
  mode: single

or like this if you want to combine multiple triggers in one automation:

- id: "91243432-708f-11ec-bf72-93a5ed09c06e"
  alias: Do something or something else
  trigger:
    - platform: event
      event_type:
        - ble_rc_to_ha
  condition: >
    {{
      trigger.event.data.method == 'keyup' and
      trigger.event.data.room == 'Living'
    }}
  action:
    - choose:
        - conditions:
            condition: template
            value_template: >
              {{
                trigger.event.data.ir_protocol == 3 and
                trigger.event.data.ir_code == 45957311
              }}
          sequence:
            service: script.send_adb_intent
        - conditions:
            condition: template
            value_template: >
              {{
                trigger.event.data.ir_protocol == 3 and
                trigger.event.data.ir_code == 45940991
              }}
          sequence:
            service: script.switch_lights_on

You can pick up the condition parameters by listenening to the ble_rc_to_ha event in the Home Assistant developer tools events section.

The other way round BLE Remote Companion listens to the event ha_to_ble_rc
Expected event data:

- event: ha_to_ble_rc
  event_data:
    room: "Living" # mandatory
    method: "keypress" # mandatory
    type: "KEYBOARD" # mandatory
    code: "KEYCODE_ENTER" # mandatory
    longpress: false # optional (keypress only)

Have a look at the keycode tables below to find out what to send.

Available methods are

Keypress is a combination of keydown followed by keyup. The optional longpress parameter adds a delay of 500ms in between.

Note: I don't have a use case for keydown or keyup yet. These methods may be deprecated and dissappear in future releases.

To add remote buttons to your frontend you can use this script:

android_tv_control:
  fields:
    room:
      description: "The Room of the device"
      example: "Living"
      required: true
      selector:
        select:
          options:
            - Living
            - Sleeping
            - Home Cinema
    method:
      description: "The method to invoke"
      example: "keypress"
      required: true
      default: keypress
      selector:
        select:
          options:
            - keypress
            - keydown
            - keyup
    type:
      description: "The Keyboard Type"
      example: "KEYBOARD"
      required: true
      default: KEYBOARD
      selector:
        select:
          options:
            - KEYBOARD
            - CONSUMER
            - APP_LAUNCHER
            - APP_CONTROL
    code:
      description: "The keycode"
      example: "KEYCODE_DPAD_UP"
      required: true
      selector:
        text:
    longpress:
      description: "Longpress"
      required: true
      default: false
      selector:
        boolean:
  sequence:
    - event: ha_to_ble_rc
      event_data:
        room: "{{ room }}"
        method: "{{ method }}"
        type: "{{ type }}"
        code: "{{ code }}"
        longpress: "{{ longpress }}"

Websocket Server

As an alternative to the Home Assistant client Remote Companion exposes a websocket server (default port: 81). Once connected you can send and receive Button presses with e.g. Node-RED (easiest IMO if you are not using Home Assistant)

ws://1.2.3.4:81/jsonrpc

Supported commands:

keypress/keyup/keydown

Parameters

Keypress is a combination of keydown followed by keyup. The optional longpress parameter adds a delay of 500ms in between.

Note: I don't have a use case for keydown or keyup yet. These methods may be deprecated and dissappear in future releases.

Example payload:

{
  "method": "keypress",
  "params": {
    "type": "KEYBOARD",
    "code": "KEYCODE_ENTER",
    "longpress": 1
  }
}

Node-RED

You can use the Node-RED websocket nodes to send and receive messages to/from your Remote Companion.
You could use it to have a remote in your home automation system or start Apps via ADB.

Configuration

Send to Remote Companion

Refer to Websocket documentation above.

Receive messages from Remote Companion

Remote Companion sends messages to all connected websocket clients if a button is pressed on a remote or in the frontend. If the pressed button has an ir code assigned the message is omitted unless 'Send assigned IR codes' is enabled in the configuration.

Message:

As a starting point you can import the Websocket example flow Screenshot

Keycode Tables

TODO: