Pylips is a Python tool to control Philips TVs (2015+) through their reverse-engineered API.
The current version of the API does not allow switching input sources anymore. For Android TVs with Google Assistant, Pylips can switch between any input sources that your TV has. For Android TVs without Google Assistant, see some options here.
Provided that you have python (version 3+) on your system, install all the dependencies first:
pip3 install -r requirements.txt
You may have to use pip
and python
instead of pip3
and python3
depending on how these tools are installed on your system.
To begin using Pylips you first need to add the ip adress of your TV to the [TV] section in the settings.ini
file. If you want to use MQTT, you will also need to fill in the [MQTT] section and set the required flags in the [DEFAULT] section:
[DEFAULT]
verbose = True # show various debug output
MQTT_listen = False # listen for MQTT commands. Requires correct [MQTT] settings
MQTT_update = False # publish status updates over MQTT. Requires correct [MQTT] settings
num_retries = 3 # number of retries when sending requests. No need to change it unless your network sucks.
update_interval = 3 # interval between updates in seconds (used if MQTT_update = True). Your TV might not appreciate lower values.
[TV]
host = # TV's ip address
port = # will be discovered automatically, but you can override it here
apiv = # will be discovered automatically, but you can override it here
user = # will be discovered automatically (if required for your TV model), but you can override it here
pass = # will be discovered automatically (if required for your TV model), but you can override it here
protocol = # will be discovered automatically, but you can override it here
ambihue_node = # will be discovered automatically, but you can override it here
[MQTT]
host = # your MQTT broker's ip address
port = # your MQTT broker's port
user = # your MQTT username
pass = # your MQTT password
TLS = False # use TLS
cert_path = # full path to your custom certificate if you are using one, otherwise leave it blank
topic_pylips = # Pylips will listen for commands to this topic
topic_status = # Pylips will send status updates to this topic
Now turn your TV on and run Pylips without any arguments to complete setting it up (it will discover your TV's API version, port and protocol, and will also pair and save the credentials if required):
python3 pylips.py
Once it's done, you are ready to use Pylips!
Security note:
To pair with the Android TVs we need to create a HMAC signature using an 88-character (?) key. As far as I can tell the key is used for pairing only. With that in mind and to make this tool as user-friendly as possible, the key is hardcoded. I see no security issues with this but if you are extremely paranoid you can change it: look for a secret_key
in the beginning of the code.
Custom config path:
You can load a custom config by specifying its absolute path with a --config
parameter:
python pylips.py --config '/home/eslavnov/repos/Pylips/some_settings.ini'
You can take advantage of some of the built-in commands or send your own custom commands.
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command %command%
Any passed arguments will override the settings in settings.ini
without overwriting them. If you have already run the discovery for new users, you don't have to specify --host
, --user
and -pass
parameters. Also skip the --user
and --pass
parameters if your TV does not have Android. Add --verbose False
to any command if you don't want to see the feedback in your terminal (useful for command line sensors).
Available built-in commands:
TV status:
powerstate
- Returns current power state of the TV ('On' or 'Off')volume
- Returns current volume and mute statuscurrent_channel
- Returns current channel (if in TV mode)current_app
- Returns current app (Android TVs only)
TV input (only for TVs with Google Assistant):
input_hdmi_1
- Switches TV's input to HDMI 1input_hdmi_2
- Switches TV's input to HDMI 2input_hdmi_3
- Switches TV's input to HDMI 3input_hdmi_4
- Switches TV's input to HDMI 4
TV remote keys:
standby
- Sends Standby keymute
- Sends Mute keyvolume_up
- Sends VolumeUp keyvolume_down
- Sends VolumeDown keychannel_up
- Sends ChannelStepUp keychannel_down
- Sends ChannelStepDown keyplay
- Sends Play keypause
- Sends Pause keyplay_pause
- Sends PlayPause keystop
- Sends Stop keyfast_forward
- Sends FastForward keyrewind
- Sends Rewind keynext
- Sends Next keyprevious
- Sends Previous keycursor_up
- Sends CursorUp keycursor_down
- Sends CursorDown keycursor_left
- Sends CursorLeft keycursor_right
- Sends CursorRight keyconfirm
- Sends Confirm keyback
- Sends Back keyhome
- Sends Home keyoptions
- Sends Options keyinfo
- Sends Info keyfind
- Sends Find keyadjust
- Sends Adjust keywatch_tv
- Sends WatchTV keyviewmode
- Sends Viewmode keyteletext
- Sends Teletext keysubtitle
- Sends Subtitle keyrecord
- Sends Record keyonline
- Sends Online keysource
- Sends Source keyambilight_onoff
- Sends AmbilightOnOff keyred
- Sends RedColour keygreen
- Sends GreenColour keyyellow
- Sends YellowColour keyblue
- Sends BlueColour keydot
- Sends Dot keydigit_0
- Sends Digit0 keydigit_1
- Sends Digit1 keydigit_2
- Sends Digit2 keydigit_3
- Sends Digit3 keydigit_4
- Sends Digit4 keydigit_5
- Sends Digit5 keydigit_6
- Sends Digit6 keydigit_7
- Sends Digit7 keydigit_8
- Sends Digit8 keydigit_9
- Sends Digit9 key
TV channels:
set_channel
- Turns a specified channel on. Requires a valid --body
argument, see the API reference to get it.list_channels
- Returns channel listlist_favorite
- Returns favorite list
Ambilight:
ambilight_on
- Turns ambilight onambilight_off
- Turns ambilight offambihue_status
- Returns the current status of 'Ambilight + Hue'ambihue_on
- Turns 'Ambilight + Hue' onambihue_off
- Turns 'Ambilight + Hue' offambilight_color
- Sets ambilight color (in HSB format). Requires a valid --body
argument: {"hue": 360, "saturation": 100, "brightness": 255}
ambilight_brightness
- Sets ambilight brightness. Requires a valid --body
argument: {"value": 10}
ambilight_video_immersive
- Sets Ambilight to 'Follow video' (Immersive)ambilight_video_standard
- Sets Ambilight to 'Follow video' (Standard)ambilight_video_natural
- Sets Ambilight to 'Follow video' (Natural)ambilight_video_vivid
- Sets Ambilight to 'Follow video' (Vivid)ambilight_video_game
- Sets Ambilight to 'Follow video' (Game)ambilight_video_comfort
- Sets Ambilight to 'Follow video' (Comfort)ambilight_video_relax
- Sets Ambilight to 'Follow video' (Relax)ambilight_color_hot_lava
- Sets Ambilight to 'Follow color' (Hot lava)ambilight_color_warm_white
- Sets Ambilight to 'Follow color' (Warm white)ambilight_color_cool_white
- Sets Ambilight to 'Follow color' (Cool white)ambilight_color_fresh_nature
- Sets Ambilight to 'Follow color' (Fresh nature)ambilight_deep_water
- Sets Ambilight to 'Follow color' (Deep water)ambilight_audio_adapt_brightness
- Sets Ambilight to 'Follow audio' (Energy Adaptive Brightness)ambilight_audio_adapt_colors
- Sets Ambilight to 'Follow audio' (Energy Adaptive Colors)ambilight_audio_vu_meter
- Sets Ambilight to 'Follow audio' (VU Meter)ambilight_audio_spectrum
- Sets Ambilight to 'Follow audio' (Spectrum Analyzer)ambilight_audio_knight_rider_1
- Sets Ambilight to 'Follow audio' (Knight Rider Clockwise)ambilight_audio_knight_rider_2
- Sets Ambilight to 'Follow audio' (Knight Rider Alternating)ambilight_audio_flash
- Sets Ambilight to 'Follow audio' (Random Pixel Flash)ambilight_audio_strobo
- Sets Ambilight to 'Follow audio' (Stroboscope)ambilight_audio_party
- Sets Ambilight to 'Follow audio' (Party)ambilight_audio_random
- Sets Ambilight to 'Follow audio' (Random Mode)
Other:
launch_app
- Launches an app (Android TVs only). Requires a valid --body
argument. See the API reference to get a list of installed apps, find your app in this list and use it as a --body
argument.power_on
- Turns on the TV even if it's in a deep sleep mode. You might need to run allow_power_on
first, although it was not needed for me.allow_power_on
- Allows to remotely power on the TV via chromecast requests.google_assistant
- Allows to pass requests to Google Assistant if your model supports it. Requires a --body
argument containing a query
with the command that you want to pass to Google Assistant. See example below.Examples of using the built-in commands:
Send Stop key:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command stop
Turn Ambilight on:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command ambilight_on
Launch YouTube:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command launch_app --body '{"id":"com.google.android.apps.youtube.tv.activity.ShellActivity-com.google.android.youtube.tv","order":0,"intent":{"action":"Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=com.google.android.youtube.tv cmp=com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.ShellActivity }","component":{"packageName":"com.google.android.youtube.tv","className":"com.google.android.apps.youtube.tv.activity.ShellActivity"}},"label":"YouTube"}'
Launch Netflix:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command launch_app --body '{"label":"Netflix","intent":{"component":{"packageName":"com.netflix.ninja","className":"com.netflix.ninja.MainActivity"},"action":"Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=com.netflix.ninja cmp=com.netflix.ninja/.MainActivity }"},"order":0,"id":"com.netflix.ninja.MainActivity-com.netflix.ninja","type":"app"}'
Launch Amazon Prime Video:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command launch_app --body '{"id":"com.amazon.amazonvideo.livingroom","order":0,"intent":{"action":"Intent{act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=com.amazon.amazonvideo.livingroom }","component":{"packageName":"com.amazon.amazonvideo.livingroom","className":"com.amazon.ignition.IgnitionActivity"}},"label":"Prime Video"}'
Launch Kodi:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command launch_app --body '{"id":"org.xbmc.kodi","order":0,"intent":{"action":"Intent{act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 pkg=org.xbmc.kodi }","component":{"packageName":"org.xbmc.kodi","className":"org.xbmc.kodi.Splash"}},"label":"Kodi"}'
Switch input to HDMI 1 using a built-in command (requires Google Assistant):
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command input_hdmi_1
Switch input to any source (for example, SCART) using Google Assistant directly:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command google_assistant --body '{"query":"SCART"}'
Control connected lights in your house using Google Assistant:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command google_assistant --body '{"query":"Turn on lights"}'
The tools exposes two general commands to talk to the TV's API: get
(sends GET request and gets back some data like ambilight mode) and post
(sends POST request that posts some data and changes something in the TV - like turning the ambilight off). You can also add custom commands to available_commands.json
.
Read the API reference first to understand available endpoints and how to use them. There are some unexpected things like:
Get method:
To use the get
method you need to provide a path to the required endpoint with a --path
argument. For example, this will send a get request to the system
endpoint (https://yourIP:1926/6/system):
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command get --path system
Post method:
To use the post
method you need to provide a path to the required endpoint with a --path
argument and the body of your POST request with a --body
argument. For example, this will send a post request to the menuitems/settings/current
endpoint with a body that will get back the status of 'Ambilight + Hue' (notice that the --body
argument needs to come inside the quotes for UNIX systems):
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command post --path menuitems/settings/current --body '{"nodes":[{"nodeid":2131230774}]}'
For Windows systems:
python3 pylips.py --host %TV's_ip_address% --user %username% --pass %password% --command post --path menuitems/settings/current --body ^"{^"^"nodes^"^":[{^"^"nodeid^"^":2131230774}]}^"
Pylips can connect to your MQTT broker to listen for commands and to publish TV status updates.
Edit the settings.ini
according to your config and simply run python3 pylips.py
without any arguments to run in MQTT mode.
Enabling MQTT_listen
in settings.ini
will allow you to send commands to a topic specified in topic_pylips
by posting a JSON message. This works pretty much the same as sending manual commands: your arguments become keys and their values - values of these keys. You can send any commands (POST, GET and built-in), but you won't get anything in return since you are just publishing a message over MQTT. Useful for POST commands that change the state of your TV, but for general GET requests you are better off using the manual mode.
See examples:
# Let's say we want to change the brightness of ambilight to max (10):
# BUILT-IN COMMANDS
# Manual mode:
python3 pylips.py --command ambilight_brightness --body '{"value":10}'
# MQTT mode:
{"command":"ambilight_brightness", "body":{"value":10}}
# POST REQUESTS
# Manual mode:
python3 pylips.py --command post --path 'menuitems/settings/update' --body '{"values":[{"value":{"Nodeid":2131230769,"Controllable":"true", "Available":"true", "string_id":"Brightness", "data":{"value":10}}}]}'
# MQTT mode:
{"command":"post", "path": "menuitems/settings/update", "body": {"values":[{"value":{"Nodeid":2131230769,"Controllable":"true", "Available":"true","string_id":"Brightness", "data":{"value":10}}}]}}
Enabling MQTT_update
in settings.ini
will publish status updates to topic_status
like these:
{"powerstate": "On", "volume": 28, "muted": false, "cur_app": "org.droidtv.settings", "ambilight": {"styleName": "FOLLOW_VIDEO", "isExpert": false, "menuSetting": "IMMERSIVE"}, "ambihue": false}
{"powerstate": "On", "volume": 28, "muted": false, "cur_app": {"app": "TV", "channel": {"channel": {"ccid": 644, "preset": "15", "name": "Comedy Central HD"}, "channelList": {"id": "allcab", "version": "19"}}}, "ambilight": {"styleName": "OFF", "isExpert": false}, "ambihue": false}
The TV's API is roughly based on JointSpace with a current version of 6.2. The only available official documentation that I was able to find is for JointSpace version 1, which is incredibly outdated.
Since no official API documentation is available, I've decided to collect and document to the best of my knowledge all endpoints that are working in API version 6+ (Philips TVs 2016-2018). Most of them should also work for API version 5 (2015 TVs). This API reference is based on:
All endpoints in API reference are tested and fully working unless explicitly marked otherwise. Any comments, new endpoints and fixes to the API reference are incredibly welcome.
The current version of the API does not allow switching input sources anymore. If your TV has Android, you have several options to switch sources:
input_hdmi_x
) or use google_assistant
. In both cases Pylips will send a local request to the Google Assistant running on the TV, which in turn will handle switching the input.F1
, F2
, etc. allow to switch sources. You can use adb
to send these key events to your TV or use this wrapper.HdmiService%2FHW9
indicates an input source (for me HdmiService%2FHW9
is HDMI 2 and HdmiService%2FHW10
is HDMI 1).
adb shell am start -a android.intent.action.VIEW -d content://android.media.tv/passthrough/org.droidtv.hdmiService%2F.HdmiService%2FHW9 -n org.droidtv.zapster/.playtv.activity.PlayTvActivity -f 0x10000000
Fixed
Changed
Fixed
Added
google_assistant
command to send queries to Google Assistant running on the TV. Check updated examples to see how you can use it.input_hdmi_1
, input_hdmi_2
, input_hdmi_3
, input_hdmi_4
commands to switch input sources (requires Google Assistant).Fixed
Added
ambilight_color_hot_lava
, ambilight_color_warm_white
, ambilight_color_cool_white
, ambilight_color_fresh_nature
, ambilight_color_deep_water
commandsFixed
Added
power_on
command that works even from sleep mode. Should work for all Android TVs, not sure about other models. Thx @neophob!Fixed
Changed
Added
Changed
Fixed
Fixed
MQTT_listen = True
+ MQTT_update = False
)Added
Fixed
Fixed
ambilight_brightness
command (manual mode)Fixed
launch_app
commandFixed
path
and body
arguments in MQTT modeFixed
Changed
Changed
power_on
to powerstate
in TV status, so now we support "Standby" and possibly other modes (MQTT-only)Changed
Added
Added
--verbose
optionAdded
Added
Initial release
~1. Finish documenting and testing all available API endpoints (January 2019)~ DONE
~2. Increase number of built-in commands~ DONE
~3. Improve error handling when sending requests~ DONE
~4. User-friendly way of changing Ambilight colors~ DONE
~5. Move settings to a config file~ DONE
~6. MQTT server support~ DONE
~7. Home assistant integration~ CANCELLED: not needed since you can now integrate it with MQTT sensors/switches.
At this point I consider the tool to be completed. No new functionality is planned, but I will fix any reported bugs and add any missing API endpoints/commands. Open an issue with your problem/suggestions.
Email: eslavnov@gmail.com; LinkedIn: https://www.linkedin.com/in/evgeny-slavnov/