import struct, os, time
from config import config, ConfigSelection, ConfigYesNo, ConfigSubsection, ConfigText
from enigma import eHdmiCEC, eActionMap
from Components.VolumeControl import VolumeControl
from Tools.StbHardware import getFPWasTimerWakeup
from enigma import eTimer
from Screens import Standby
from Tools import Directories, Notifications
from time import time
import xml.etree.cElementTree
config.hdmicec = ConfigSubsection()
config.hdmicec.enabled = ConfigYesNo(default = True)
config.hdmicec.control_tv_standby = ConfigYesNo(default = True)
config.hdmicec.control_tv_wakeup = ConfigYesNo(default = True)
config.hdmicec.report_active_source = ConfigYesNo(default = True)
config.hdmicec.report_active_menu = ConfigYesNo(default = True)
config.hdmicec.handle_tv_standby = ConfigYesNo(default = True)
config.hdmicec.handle_tv_wakeup = ConfigYesNo(default = True)
config.hdmicec.tv_wakeup_detection = ConfigSelection(
choices = {
"wakeup": _("Wakeup"),
"tvreportphysicaladdress": _("TV physical address report"),
"sourcerequest": _("Source request"),
"streamrequest": _("Stream request"),
"osdnamerequest": _("OSD name request"),
"vendorid": _("Vendor ID (LG)"),
"activity": _("Any activity"),
},
default = "streamrequest")
config.hdmicec.fixed_physical_address = ConfigText(default = "0.0.0.0")
config.hdmicec.volume_forwarding = ConfigYesNo(default = False)
config.hdmicec.control_receiver_wakeup = ConfigYesNo(default = False)
config.hdmicec.control_receiver_standby = ConfigYesNo(default = False)
config.hdmicec.handle_deepstandby_events = ConfigYesNo(default = False)
choicelist = []
for i in (10, 50, 100, 150, 250):
choicelist.append(("%d" % i, "%d ms" % i))
config.hdmicec.minimum_send_interval = ConfigSelection(default = "0", choices = [("0", _("Disabled"))] + choicelist)
class HdmiCec:
def __init__(self):
assert not HdmiCec.instance, "only one HdmiCec instance is allowed!"
HdmiCec.instance = self
self.wait = eTimer()
self.wait.timeout.get().append(self.sendCmd)
self.queue = []
eHdmiCEC.getInstance().messageReceived.get().append(self.messageReceived)
config.misc.standbyCounter.addNotifier(self.onEnterStandby, initial_call = False)
config.misc.DeepStandby.addNotifier(self.onEnterDeepStandby, initial_call = False)
self.setFixedPhysicalAddress(config.hdmicec.fixed_physical_address.value)
self.logicaladdress = eHdmiCEC.getInstance().getLogicalAddress()
self.saveVolUp = None
self.saveVolDown = None
self.saveVolMute = None
self.volumeForwardingDestination = 0
config.hdmicec.volume_forwarding.addNotifier(self.configVolumeForwarding)
config.hdmicec.enabled.addNotifier(self.configVolumeForwarding)
uptime = float(open("/proc/uptime", "r").read().split()[0])
if config.hdmicec.handle_deepstandby_events.value and uptime < 120:
filename = Directories.resolveFilename(Directories.SCOPE_CONFIG, "timers.xml")
try:
doc = xml.etree.cElementTree.parse(filename)
except:
doc = None
if doc:
root = doc.getroot()
for timer in root.findall("timer"):
begin = int(timer.get("begin"))
disabled = long(timer.get("disabled") or "0")
justplay = long(timer.get("justplay") or "0")
always_zap = long(timer.get("always_zap") or "0")
if begin < time() or begin > time() + 360 or disabled or justplay or always_zap:
continue
if Standby.inStandby is None:
Notifications.AddNotification(Standby.Standby)
return
self.wakeupMessages()
def getPhysicalAddress(self):
physicaladdress = eHdmiCEC.getInstance().getPhysicalAddress()
hexstring = '%04x' % physicaladdress
return hexstring[0] + '.' + hexstring[1] + '.' + hexstring[2] + '.' + hexstring[3]
def setFixedPhysicalAddress(self, address):
if address != config.hdmicec.fixed_physical_address.value:
config.hdmicec.fixed_physical_address.value = address
config.hdmicec.fixed_physical_address.save()
hexstring = address[0] + address[2] + address[4] + address[6]
eHdmiCEC.getInstance().setFixedPhysicalAddress(int(float.fromhex(hexstring)))
def sendMessage(self, address, message):
cmd = 0
data = ''
if message == "wakeup":
cmd = 0x04
elif message == "sourceactive":
address = self.logicaladdress * 0x10 + 0x0f # use broadcast for active source command
cmd = 0x82
physicaladdress = eHdmiCEC.getInstance().getPhysicalAddress()
data = str(struct.pack('BB', int(physicaladdress/256), int(physicaladdress%256)))
elif message == "standby":
cmd = 0x36
elif message == "sourceinactive":
physicaladdress = eHdmiCEC.getInstance().getPhysicalAddress()
cmd = 0x9d
data = str(struct.pack('BB', int(physicaladdress/256), int(physicaladdress%256)))
elif message == "menuactive":
cmd = 0x8e
data = str(struct.pack('B', 0x00))
elif message == "menuinactive":
cmd = 0x8e
data = str(struct.pack('B', 0x01))
elif message == "givesystemaudiostatus":
cmd = 0x7d
address = self.logicaladdress * 0x10 + 0x05
elif message == "setsystemaudiomode":
cmd = 0x70
address = self.logicaladdress * 0x10 + 0x05
physicaladdress = eHdmiCEC.getInstance().getPhysicalAddress()
data = str(struct.pack('BB', int(physicaladdress/256), int(physicaladdress%256)))
elif message == "osdname":
address = self.logicaladdress * 0x10
cmd = 0x47
data = "Enigma2"
elif message == "poweractive":
address = self.logicaladdress * 0x10
cmd = 0x90
data = str(struct.pack('B', 0x00))
elif message == "powerinactive":
address = self.logicaladdress * 0x10
cmd = 0x90
data = str(struct.pack('B', 0x01))
elif message == "poweron":
address = self.logicaladdress * 0x10
cmd = 0x90
data = str(struct.pack('B', 0x02))
elif message == "reportaddress":
address = self.logicaladdress * 0x10 + 0x0f # use broadcast address
cmd = 0x84
physicaladdress = eHdmiCEC.getInstance().getPhysicalAddress()
devicetype = eHdmiCEC.getInstance().getDeviceType()
data = str(struct.pack('BBB', int(physicaladdress/256), int(physicaladdress%256), devicetype))
elif message == "vendorid":
address = self.logicaladdress * 0x10 + 0x0f
cmd = 0x87
data = '\x00\xE0\x91'
elif message == "keypoweron":
cmd = 0x44
data = str(struct.pack('B', 0x6d))
elif message == "keypoweroff":
cmd = 0x44
data = str(struct.pack('B', 0x6c))
elif message == "playstatus":
address = self.logicaladdress * 0x10
cmd = 0x1B
data = '\x20'
elif message == "vendorcommand0":
address = self.logicaladdress * 0x10
cmd = 0x89
data = '\x02\x05'
elif message == "vendorcommand1":
address = self.logicaladdress * 0x10
cmd = 0x89
data = '\xA1\x01'
elif message == "vendorcommand2":
address = self.logicaladdress * 0x10
cmd = 0x89
data = '\x0C\x05'
elif message == "vendorcommand3":
address = self.logicaladdress * 0x10
cmd = 0x89
data = '\x05\x04'
if cmd:
if config.hdmicec.minimum_send_interval.value != "0":
self.queue.append((address, cmd, data))
if not self.wait.isActive():
self.wait.start(int(config.hdmicec.minimum_send_interval.value), True)
else:
eHdmiCEC.getInstance().sendMessage(address, cmd, data, len(data))
def sendCmd(self):
if len(self.queue):
(address, cmd, data) = self.queue.pop(0)
eHdmiCEC.getInstance().sendMessage(address, cmd, data, len(data))
self.wait.start(int(config.hdmicec.minimum_send_interval.value), True)
def sendMessages(self, address, messages):
for message in messages:
self.sendMessage(address, message)
def wakeupMessages(self):
if config.hdmicec.enabled.value:
messages = []
if config.hdmicec.control_tv_wakeup.value:
messages.append("wakeup")
if config.hdmicec.report_active_source.value:
messages.append("sourceactive")
if config.hdmicec.report_active_menu.value:
messages.append("menuactive")
if messages:
self.sendMessages(0, messages)
if config.hdmicec.control_receiver_wakeup.value:
self.sendMessage(5, "keypoweron")
self.sendMessage(5, "setsystemaudiomode")
def standbyMessages(self):
if config.hdmicec.enabled.value:
messages = []
if config.hdmicec.control_tv_standby.value:
messages.append("standby")
else:
if config.hdmicec.report_active_source.value:
messages.append("sourceinactive")
if config.hdmicec.report_active_menu.value:
messages.append("menuinactive")
if messages:
self.sendMessages(0, messages)
if config.hdmicec.control_receiver_standby.value:
self.sendMessage(5, "keypoweroff")
self.sendMessage(5, "standby")
def onLeaveStandby(self):
self.wakeupMessages()
def onEnterStandby(self, configElement):
from Screens.Standby import inStandby
inStandby.onClose.append(self.onLeaveStandby)
self.standbyMessages()
def onEnterDeepStandby(self, configElement):
if config.hdmicec.handle_deepstandby_events.value:
self.standbyMessages()
def standby(self):
from Screens.Standby import Standby, inStandby
if not inStandby:
from Tools import Notifications
Notifications.AddNotification(Standby)
def wakeup(self):
from Screens.Standby import Standby, inStandby
if inStandby:
inStandby.Power()
def messageReceived(self, message):
if config.hdmicec.enabled.value:
from Screens.Standby import inStandby
cmd = message.getCommand()
data = 16 * '\x00'
length = message.getData(data, len(data))
if cmd == 0x00: # feature abort
if data[0] == '\x44':
print 'eHdmiCec: volume forwarding not supported by device %02x'%(message.getAddress())
self.volumeForwardingDisable()
elif cmd == 0x89:
if data[0] == '\x01':
self.sendMessage(message.getAddress(), 'vendorcommand0')
if data[0] == '\xA0':
if inStandby:
self.sendMessage(message.getAddress(), 'poweron')
else:
self.sendMessage(message.getAddress(), 'poweractive')
if data[0] == '\x0B':
self.sendMessage(message.getAddress(), 'vendorcommand2')
if data[0] == '\x04':
self.sendMessage(message.getAddress(), 'vendorcommand3')
elif cmd == 0x1A: # request name
self.sendMessage(message.getAddress(), 'playstatus')
elif cmd == 0x46: # request name
self.sendMessage(message.getAddress(), 'osdname')
elif cmd == 0x7e or cmd == 0x72: # system audio mode status
if data[0] == '\x01':
self.volumeForwardingDestination = 5; # on: send volume keys to receiver
else:
self.volumeForwardingDestination = 0; # off: send volume keys to tv
if config.hdmicec.volume_forwarding.value:
print 'eHdmiCec: volume forwarding to device %02x enabled'%(self.volumeForwardingDestination)
self.volumeForwardingEnable()
elif cmd == 0x8f: # request power status
if inStandby:
self.sendMessage(message.getAddress(), 'powerinactive')
else:
self.sendMessage(message.getAddress(), 'poweractive')
elif cmd == 0x83: # request address
self.sendMessage(message.getAddress(), 'reportaddress')
elif cmd == 0x86: # request streaming path
physicaladdress = ord(data[0]) * 256 + ord(data[1])
ouraddress = eHdmiCEC.getInstance().getPhysicalAddress()
if physicaladdress == ouraddress:
if not inStandby:
if config.hdmicec.report_active_source.value:
self.sendMessage(message.getAddress(), 'sourceactive')
elif cmd == 0x85: # request active source
if not inStandby:
if config.hdmicec.report_active_source.value:
self.sendMessage(message.getAddress(), 'sourceactive')
elif cmd == 0x8c: # request vendor id
self.sendMessage(message.getAddress(), 'vendorid')
elif cmd == 0x8d: # menu request
requesttype = ord(data[0])
if requesttype == 2: # query
if inStandby:
self.sendMessage(message.getAddress(), 'menuinactive')
else:
self.sendMessage(message.getAddress(), 'menuactive')
# handle standby request from the tv
if cmd == 0x36 and config.hdmicec.handle_tv_standby.value:
self.standby()
# handle wakeup requests from the tv
if config.hdmicec.handle_tv_wakeup.value:
if cmd == 0x04 and config.hdmicec.tv_wakeup_detection.value == "wakeup":
self.wakeup()
elif cmd == 0x84 and config.hdmicec.tv_wakeup_detection.value == "tvreportphysicaladdress":
if (ord(data[0]) * 256 + ord(data[1])) == 0 and ord(data[2]) == 0:
self.wakeup()
elif cmd == 0x85 and config.hdmicec.tv_wakeup_detection.value == "sourcerequest":
self.wakeup()
elif cmd == 0x86 and config.hdmicec.tv_wakeup_detection.value == "streamrequest":
physicaladdress = ord(data[0]) * 256 + ord(data[1])
ouraddress = eHdmiCEC.getInstance().getPhysicalAddress()
if physicaladdress == ouraddress:
self.wakeup()
elif cmd == 0x46 and config.hdmicec.tv_wakeup_detection.value == "osdnamerequest":
self.wakeup()
elif cmd == 0x87 and (ord(data[0])==0x00 and ord(data[1])==0xE0 and ord(data[2])==0x91) and config.hdmicec.tv_wakeup_detection.value == "vendorid":
self.wakeup()
elif cmd != 0x36 and config.hdmicec.tv_wakeup_detection.value == "activity":
self.wakeup()
def configVolumeForwarding(self, configElement):
if config.hdmicec.enabled.value and config.hdmicec.volume_forwarding.value:
self.volumeForwardingEnable()
self.sendMessage(0x05, 'givesystemaudiostatus')
else:
self.volumeForwardingDisable()
def volumeForwardingEnable(self):
if self.saveVolMute is None:
self.saveVolUp = VolumeControl.volUp
self.saveVolDown = VolumeControl.volDown
self.saveVolMute = VolumeControl.volMute
VolumeControl.volUp = self.volUp
VolumeControl.volDown = self.volDown
VolumeControl.volMute = self.volMute
def volumeForwardingDisable(self):
if self.saveVolMute is not None:
VolumeControl.volUp = self.saveVolUp
VolumeControl.volDown = self.saveVolDown
VolumeControl.volMute = self.saveVolMute
self.saveVolUp = None
self.saveVolDown = None
self.saveVolMute = None
def volUp(self):
cmd = 0x44
data = str(struct.pack('B', 0x41))
eHdmiCEC.getInstance().sendMessage(self.logicaladdress * 0x10 + self.volumeForwardingDestination, cmd, data, len(data))
def volDown(self):
cmd = 0x44
data = str(struct.pack('B', 0x42))
eHdmiCEC.getInstance().sendMessage(self.logicaladdress * 0x10 + self.volumeForwardingDestination, cmd, data, len(data))
def volMute(self):
cmd = 0x44
data = str(struct.pack('B', 0x43))
eHdmiCEC.getInstance().sendMessage(self.logicaladdress * 0x10 + self.volumeForwardingDestination, cmd, data, len(data))
hdmi_cec = HdmiCec()