Skip to content
This repository has been archived by the owner on Jul 10, 2024. It is now read-only.

Support for notifications #37

Open
kylerw opened this issue Apr 9, 2017 · 7 comments
Open

Support for notifications #37

kylerw opened this issue Apr 9, 2017 · 7 comments
Labels

Comments

@kylerw
Copy link

kylerw commented Apr 9, 2017

Would be great to be able to send notifications to the TV

@AnderssonPeter
Copy link

AnderssonPeter commented Apr 11, 2017

This would be awesome but the question is if the api that the tv's provides supports this functionality.

@Ape Ape added the question label Nov 2, 2017
@Ape Ape changed the title [REQUEST] Support for notifications Support for notifications Nov 2, 2017
@tuxuser
Copy link

tuxuser commented Jul 21, 2018

Tested on B-series successfully

Could everybody with a different model please give it a try

"""
Send notifications to Samsung TV via uPnP MessageBox service

Tested on B-Series TV
UPDATE: Added rendering control

by tuxuser (2018/07/21) https://github.com/tuxuser
"""
import sys
import argparse

import requests
import upnpclient
from datetime import datetime
from lxml import etree


class SamsungTvNotifier(object):
    def __init__(self, ip, port):
        self._ip = ip
        self._port = port

        # MessageBox standard parameters
        self._message_id = 0
        self.message_type = 'text/xml'

        # RenderingControl standard parameters
        self.instance_id = 0

        self.notify_service = None
        self.rendering_service = None

    @property
    def message_id(self):
        self._message_id += 1
        return str(self._message_id)

    @staticmethod
    def get_etree_without_root(root_node):
        ret = b''
        for element in root_node:
            ret += etree.tostring(element)
        return ret.decode('utf-8')

    @staticmethod
    def build_sms_notification(sms_text, sender_name, sender_number, receiver_name, receiver_number,
                               receive_dt=datetime.now()):
        root = etree.Element("root")
        etree.SubElement(root, "Category").text = "SMS"
        etree.SubElement(root, "DisplayType").text = "Maximum"

        receive_time = etree.SubElement(root, "ReceiveTime")
        etree.SubElement(receive_time, "Date").text = receive_dt.strftime('%Y-%m-%d')
        etree.SubElement(receive_time, "Time").text = receive_dt.strftime('%H:%M:%S')

        receiver = etree.SubElement(root, "Receiver")
        etree.SubElement(receiver, "Number").text = receiver_number
        etree.SubElement(receiver, "Name").text = receiver_name

        sender = etree.SubElement(root, "Sender")
        etree.SubElement(sender, "Number").text = sender_number
        etree.SubElement(sender, "Name").text = sender_name

        etree.SubElement(root, "Body").text = sms_text
        return SamsungTvNotifier.get_etree_without_root(root)

    @staticmethod
    def build_call_notification(caller_name, caller_number, callee_name, callee_number,
                                call_dt=datetime.now()):
        root = etree.Element("root")
        etree.SubElement(root, "Category").text = "Incoming Call"
        etree.SubElement(root, "DisplayType").text = "Maximum"

        call_time = etree.SubElement(root, "CallTime")
        etree.SubElement(call_time, "Date").text = call_dt.strftime('%Y-%m-%d')
        etree.SubElement(call_time, "Time").text = call_dt.strftime('%H:%M:%S')

        callee = etree.SubElement(root, "Callee")
        etree.SubElement(callee, "Number").text = callee_number
        etree.SubElement(callee, "Name").text = callee_name

        caller = etree.SubElement(root, "Caller")
        etree.SubElement(caller, "Number").text = caller_number
        etree.SubElement(caller, "Name").text = caller_name
        return SamsungTvNotifier.get_etree_without_root(root)

    @staticmethod
    def build_schedule_notification(subject, location, schedule_text,
                                    owner_name, owner_number,
                                    start_dt, end_dt):
        root = etree.Element("root")
        etree.SubElement(root, "Category").text = "Schedule Reminder"
        etree.SubElement(root, "DisplayType").text = "Maximum"

        start_time = etree.SubElement(root, "StartTime")
        etree.SubElement(start_time, "Date").text = start_dt.strftime('%Y-%m-%d')
        etree.SubElement(start_time, "Time").text = start_dt.strftime('%H:%M:%S')

        owner = etree.SubElement(root, "Owner")
        etree.SubElement(owner, "Number").text = owner_number
        etree.SubElement(owner, "Name").text = owner_name

        etree.SubElement(root, "Subject").text = subject

        end_time = etree.SubElement(root, "EndTime")
        etree.SubElement(end_time, "Date").text = end_dt.strftime('%Y-%m-%d')
        etree.SubElement(end_time, "Time").text = end_dt.strftime('%H:%M:%S')

        etree.SubElement(root, "Location").text = location
        etree.SubElement(root, "Body").text = schedule_text

        return SamsungTvNotifier.get_etree_without_root(root)

    def _initialize_notification(self):
        messagebox_url = 'http://{addr}:{port}/pmr/PersonalMessageReceiver.xml'.format(
            addr=self._ip, port=self._port
        )

        try:
            device = upnpclient.Device(messagebox_url)
        except requests.exceptions.ConnectTimeout as e:
            raise Exception('Device looks unavailable! msg: {0}'.format(e))

        service = device.service_map.get('MessageBoxService')
        if not service:
            raise Exception('MessageBoxService not found')

        return service

    def _initialize_rendering(self):
        renderer_url = 'http://{addr}:{port}/dmr/SamsungMRDesc.xml'.format(
            addr=self._ip, port=self._port
        )

        try:
            device = upnpclient.Device(renderer_url)
        except requests.exceptions.ConnectTimeout as e:
            raise Exception('Device looks unavailable! msg: {0}'.format(e))

        service = device.service_map.get('RenderingControl')
        if not service:
            raise Exception('RenderingControk not found')

        return service

    def send_notification(self, notification_body):
        if not self.notify_service:
            self.notify_service = self._initialize_notification()

        try:
            add_message = self.notify_service['AddMessage']
        except KeyError:
            raise Exception('Notification action \'AddMessage\' is unavailable')

        return add_message(MessageID=self.message_id, MessageType=self.message_type,
                           Message=notification_body)

    def send_rendering_change(self, endpoint, **kwargs):
        if not self.rendering_service:
            self.rendering_service = self._initialize_rendering()

        try:
            rendering_action = self.rendering_service[endpoint]
        except KeyError:
            raise Exception('Rendering control \'{0}\' not existing!'.format(endpoint))

        return rendering_action(InstanceID=self.instance_id, **kwargs)

    def list_presets(self):
        return self.send_rendering_change('ListPresets')

    def select_preset(self, preset_name):
        return self.send_rendering_change('SelectPreset', PresetName=preset_name)

    def get_mute(self, channel='Master'):
        resp = self.send_rendering_change('GetMute', Channel=channel)
        return resp['CurrentMute']

    def set_mute(self, do_mute, channel='Master'):
        if do_mute:
            desired_mute = 'true'
        else:
            desired_mute = 'false'
        return self.send_rendering_change('SetMute', Channel=channel, DesiredMute=desired_mute)

    def get_volume(self, channel='Master'):
        resp = self.send_rendering_change('GetVolume', Channel=channel)
        return resp['CurrentVolume']

    def set_volume(self, volume, channel='Master'):
        return self.send_rendering_change('SetVolume', Channel=channel, DesiredVolume=volume)

    def get_brightness(self):
        resp = self.send_rendering_change('GetBrightness')
        return resp['CurrentBrightness']

    def set_brightness(self, brightness):
        return self.send_rendering_change('SetBrightness', DesiredBrightness=brightness)

    def get_constrast(self):
        resp = self.send_rendering_change('GetContrast')
        return resp['CurrentContrast']

    def set_constrast(self, constrast):
        return self.send_rendering_change('SetContrast', DesiredContrast=constrast)

    def get_sharpness(self):
        resp = self.send_rendering_change('GetSharpness')
        return resp['CurrentSharpness']

    def set_sharpness(self, sharpness):
        return self.send_rendering_change('SetSharpness', DesiredSharpness=sharpness)

    def get_color_temperature(self):
        resp = self.send_rendering_change('GetColorTemperature')
        return resp['CurrentColorTemperature']

    def set_color_temperature(self, color_temp):
        return self.send_rendering_change('SetColorTemperature', DesiredColorTemperature=color_temp)

    def get_slideshow_effect(self):
        resp = self.send_rendering_change('X_GetSlideShowEffect')
        return resp['SlideShowEffect']

    def set_slideshow_effect(self, effect):
        return self.send_rendering_change('X_SetSlideShowEffect', SlideShowEffect=effect)

    def get_image_scale(self):
        return self.send_rendering_change('X_GetImageScale')

    def set_image_scale(self):
        return self.send_rendering_change('X_SetImageScale')

    def get_image_rotation(self):
        return self.send_rendering_change('X_GetImageRotation')

    def set_image_rotation(self):
        return self.send_rendering_change('X_SetImageRotation')

if __name__ == '__main__':
    parser = argparse.ArgumentParser('Samsung TV Notifier')
    parser.add_argument('ip',
                        help='IP address of target Samsung TV')
    parser.add_argument('--port', '-p', default=52235,
                        help='Port of uPnP service')

    args = parser.parse_args()

    notifier = SamsungTvNotifier(args.ip, args.port)

    body = notifier.build_sms_notification('Hello, I sent you a SMS', 'tuxuser', '1337', 'samsungctl', '123')
    ret = notifier.send_notification(body)

    notifier.set_mute(False)

@tomhash2
Copy link

tomhash2 commented Oct 5, 2018

On my UE55MU6172 doesn't work :(

root@HomeAssistant:~/tizen# ./send.py --port 8001 192.168.10.12
Traceback (most recent call last):
File "./send.py", line 254, in
ret = notifier.send_notification(body)
File "./send.py", line 150, in send_notification
self.notify_service = self._initialize_notification()
File "./send.py", line 122, in _initialize_notification
device = upnpclient.Device(messagebox_url)
File "/usr/local/lib/python3.4/dist-packages/upnpclient/upnp.py", line 107, in init
resp.raise_for_status()
File "/usr/local/lib/python3.4/dist-packages/requests/models.py", line 935, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: http://192.168.10.12:8001/pmr/PersonalMessageReceiver.xml

@jhanson999
Copy link

Defalt Port:
root@johnsubuntu:~/scripts# python send.py 10.0.0.92
Traceback (most recent call last):
File "send.py", line 252, in
ret = notifier.send_notification(body)
File "send.py", line 148, in send_notification
self.notify_service = self._initialize_notification()
File "send.py", line 120, in _initialize_notification
device = upnpclient.Device(messagebox_url)
File "/usr/local/lib/python2.7/dist-packages/upnpclient/upnp.py", line 105, in init
headers=self.http_headers
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 533, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 646, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 516, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='10.0.0.92', port=52235): Max retries exceeded with url: /pmr/PersonalMessageReceiver.xml (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f1154009090>: Failed to establish a new connection: [Errno 111] Connection refused',))

Port 8001:
root@johnsubuntu:~/scripts# python send.py --port 8001 10.0.0.92
Traceback (most recent call last):
File "send.py", line 252, in
ret = notifier.send_notification(body)
File "send.py", line 148, in send_notification
self.notify_service = self._initialize_notification()
File "send.py", line 120, in _initialize_notification
device = upnpclient.Device(messagebox_url)
File "/usr/local/lib/python2.7/dist-packages/upnpclient/upnp.py", line 107, in init
resp.raise_for_status()
File "/usr/local/lib/python2.7/dist-packages/requests/models.py", line 940, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: http://10.0.0.92:8001/pmr/PersonalMessageReceiver.xml

Not working for me either. Model: KS8000

@whittin3
Copy link

Is this possible? Any progress?

@cheesecake441
Copy link

Bought a 55" Samsung TV recently and it would be really great to get this working so I can be reminded about stuffs. Please and thank you <3

@B-malais
Copy link

I got the notification pop up to allow my device on my UN75CU7000FXZA but then I get the same 404 error as @tomhash2. Any updates?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

9 participants