As I Please

MTのいんすとーるの練習と、その他びぼうろく・・・

ビエラ panasonic のIPコントロール(DT5)とめざましじゃんけん

古いパナソニックビエラ(うちのはDT5)でリモコン操作(赤外線)を、IP経由で行う。 nature remo で赤外線飛ばすのは時に安定しないしプログラマブルにはほど遠い感じがするので、 IPでやれないかと。 手法は、
  1. upnp でIPアドレス、送信先を取得
  2. soapで投げつける。
という方向で。 参照、利用したのは、pyvieraというライブラリ。 古いので認証なしで使える。ただし、python2 用のようで、viera.py を改修。urlilb2を使っていたり、海外のリモコンエミューレトなのでいくつかのボタンが無い(NRC_DATA-ONOFF:dボタン、NRC_PROG-ONOFF:番組表、NRC_SPLIT-ONOFF:2画面?)ので、これらにちょっとだけ対処。ドイツのPanasonic TV mit IPS Steuernというものを参考に。dボタンのコードがなかなか見つからなかった。改修した viera.pyはこちら
import urllib.request,urllib.error, urllib.parse
class Viera(object):
    def __init__(self, hostname, control_url, service_type):
        self.hostname = hostname
        self.control_url = control_url
        self.service_type = service_type
        self.sendkey_action = Action('X_SendKey', ('X_KeyEvent',))
    def _sendkey(self, slug):
        req = self.sendkey_action.to_soap_request(
            self.control_url,
            self.hostname,
            self.service_type,
            (slug,),
        )
        urllib.request.urlopen(req).read()
    def __unicode__(self):
        return '' % (
            self.hostname,
            self.control_url,
            self.service_type,
        )
    def vol_up(self):
        self._sendkey('NRC_VOLUP-ONOFF')
    def vol_down(self):
        self._sendkey('NRC_VOLDOWN-ONOFF')
    def mute(self):
        self._sendkey('NRC_MUTE-ONOFF')
    def num(self, number):
        for digit in str(number):
            self._sendkey('NRC_D%s-ONOFF' % digit)
    def power(self):
        self._sendkey('NRC_TV-ONOFF')
    def toggle_3D(self):
        self._sendkey('NRC_3D-ONOFF')
    def toggle_SDCard(self):
        self._sendkey('NRC_SD_CARD-ONOFF')
    def red(self):
        self._sendkey('NRC_RED-ONOFF')
    def green(self):
        self._sendkey('NRC_GREEN-ONOFF')
    def yellow(self):
        self._sendkey('NRC_YELLOW-ONOFF')
    def blue(self):
        self._sendkey('NRC_BLUE-ONOFF')
    def vtools(self):
        self._sendkey('NRC_VTOOLS-ONOFF')
    def cancel(self):
        self._sendkey('NRC_CANCEL-ONOFF')
    def option(self):
        self._sendkey('NRC_SUBMENU-ONOFF')
    def Return(self):
        self.sendkey('NRC_RETURN-ONOFF')
    def enter(self):
        self._sendkey('NRC_ENTER-ONOFF')
    def right(self):
        self._sendkey('NRC_RIGHT-ONOFF')
    def left(self):
        self._sendkey('NRC_LEFT-ONOFF')
    def up(self):
        self._sendkey('NRC_UP-ONOFF')
    def down(self):
        self._sendkey('NRC_DOWN-ONOFF')
    def display(self):
        self._sendkey('NRC_DISP_MODE-ONOFF')
    def menu(self):
        self._sendkey('NRC_MENU-ONOFF')
    def connect(self):
        self._sendkey('NRC_INTERNET-ONOFF')
    def link(self):
        self._sendkey('NRC_VIERA_LINK-ONOFF')
    def guide(self):
        self._sendkey('NRC_EPG-ONOFF')
    def text(self):
        self._sendkey('NRC_TEXT-ONOFF')
    def subtitles(self):
        self._sendkey('NRC_STTL-ONOFF')
    def info(self):
        self._sendkey('NRC_INFO-ONOFF')
    def index(self):
        self._sendkey('NRC_INDEX-ONOFF')
    def hold(self):
        self._sendkey('NRC_HOLD-ONOFF')
    def d(self):
        self._sendkey('NRC_DATA-ONOFF')
    def prog(self):
        self._sendkey('NRC_PROG-ONOFF')
    def split(self):
        self._sendkey('NRC_SPLIT-ONOFF')
class Action(object):
    def __init__(self, name, arguments):
        self.name = name
        self.arguments = arguments
    def to_soap_request(self, url, hostname, service_type, values):
        assert len(values) == len(self.arguments)
        params = ''.join(['<%s>%s' % (arg, value, arg) for arg, value in zip(self.arguments, values)])
        soap_body = (
            ''
            ''
            ''
            ''
            '%(params)s'
            ''
            ''
        ''
        ) % {
            'method_name': self.name,
            'service_type': service_type,
            'params': params,
        }
        headers = {
            'Host': hostname,
            'Content-Length': len(soap_body),
            'Content-Type': 'text/xml',
            'SOAPAction': '"%s#%s"' % (service_type, self.name),
        }
        soap_body = soap_body.encode()
#        headers = urllib.parse.urlencode(headers).encode()
        req = urllib.request.Request(url, soap_body, headers)
        return req
テスト稼働で、フジテレビめざましじゃんけんを自動で毎日やらせてみた。
import socket
import urllib.request,urllib.error,urllib.parse
from urllib.request import urlopen
from viera import Viera
from pyviera import VieraFinder
import time
import random
tv = Viera('(IP_address)','http://(IP_address):55000/nrc/control_0','urn:panasonic-com:service:p00NetworkControl:1')
if __name__ == '__main__':
    tv.num(8)
    time.sleep(5)
    tv.info()
    for i in range(20):
        button = random.choice(('tv.blue()','tv.red()','tv.green()'))
        eval(button)
        time.sleep(3)
これを、月~金は 05:57,06:57,07:34,07:57に、土は 07:37,08:21 にcronで起動。 テレビがついていれば、IP経由でch8 に変更して、ランダムに青赤緑を投げつける。 半年以上動かしていて、一週間で最大300点オーバーの週もあった。 ちなみに、最近のvieraはアプリ最初のアクセス時に認証を求めるようで、そうするとこちらのライブラリが良さそう。 https://github.com/florianholzapfel/panasonic-viera/issues/9
https://github.com/florianholzapfel/panasonic-viera/blob/master/panasonic_viera/__init__.py PINコードを入力して、credential情報を取得し使い回す必要があるようだ。

ps.1
めざましじゃんけんは、画像自動認識や勝率アップのためいろいろ面白いことをやってる人がいて楽しい。 テレビの画像を認識して、じゃんけんするタイミングや勝敗結果も拾うなんてことをやってるひとがいる。 https://www.miki-ie.com/column/mezamashi-janken-machine-learning/ ここまでいろいろ楽しめるとは。 しかし、AI学習で勝率アップって・・・どこまでホント???
ps.2
めざましじゃんけん、勝ち20点引き分け10点負け5点の平均値 35/3 =11.666... 、1週間で22回(月~金4回、土2回)なので、1週間の期待値は256.666... 分散が116.666..., 標準偏差が 10.8 くらいの分布か。 正規分布じゃないけど、300点越えは 4σくらいの事象ですか。

コメントする