trainman419 / python-cec

Other
170 stars 42 forks source link

Change HDMI Source on TV (Device 0) #10

Closed pimok closed 6 years ago

pimok commented 9 years ago

Thank you for your great work!

Is there an API function, using the current bindings, that lets me select the source to be displayed on the TV? ActiveSource chooses "self", but I want to be able to tell the TV choose HDMI1, HDMI2 or HDMI3 using the API.

Thanks again. pimok

trainman419 commented 9 years ago

libcec doesn't provide any bindings for changing the input on a specific device.

I suspect this is because the CEC standard doesn't specify commands for changing inputs.

For my receiver, there are vendor-specific remote keypresses that I can send to change inputs (Device.set_av_input). I suspect your TV has a similar set of keypresses, but they're probably vendor-specific. If you can find or figure out which keypresses to send, I can help provide a better API for sending them.

pimok commented 9 years ago

Thanks for your feednback.

Unfortunately on my samsung, pressing the remote control (av input)SOURCE and then NUM3 brings an on-screen error message and only allows the arrows to select the source.

There seems to be a CEC command sequence which tells the TV to select an input. I do not know if the TV reacts directly to this command or if one of its sources reacts to the CEC command and selects itself to be the source on the TV. This does actually work when I type in the sequence as a tx command using cec-client.

The CEC command for "TV please select HDMI2 as av input" on the bus looks like; 1f 82 20 00 1 is the initiator (me ? eg RPi?) f is CECDEVICE_BROADCAST 82 is CEC_OPCODE_ACTIVE_SOURCE 20 00 is HDMI2

This is output by the following libcec code: bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE); command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));

return Transmit(command, false, bIsReply); }

Making a binding to this function is probably difficult as the network structure of the C++ classes is quite deep and maybe the initiator may become wrong.

If you could implement a binding for a function that gives direct access to Transmit then this could be used to send CEC packets on the bus and bypassing the network structure. Something like a python call cec.transmit("1f822000")

Possible implementation in your bindings code cec.cpp:

static unsigned char from_hex(char c) { return (c>='0' && c<='9') ? (c-'0'): (c>='a' && c<='f') ? (c-'a'+10): (c>='A' && c<='F') ? (c-'A'+10): 0; }

static unsigned char from_hex2(char hi, char lo) { return from_hex(hi)<<4+from_hex(lo); }

static PyObject * transmit(PyObject * args) { const char * input = NULL; if( PyArg_ParseTuple(args, "s:transmit", &input) && input && strlen(input)>=4) { cec_command data; bool success; Py_BEGIN_ALLOW_THREADS data.initiator = from_hex(input[0]); data.destination = from_hex(input[1]); data.opcode = from_hex2(input[2], input[3]); data.opcode_set = 1; for (int i= 4; input[i] && input[i+1]; i+= 2) data.PushBack(from_hex2(input[i], input[i+1])); success = CEC_adapter->Transmit(data); Py_END_ALLOW_THREADS if( success ) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } else { return NULL; } }

Thanks again pimok

trainman419 commented 9 years ago

If you have suggested code changes, please submit them as a pull request.

That said, I recommend a few changes to this before submitting it:

If libcec is already implementing this as part of their setActiveSource call, it may be better to implement the wrapper for that; particularly since it's already on the TODO list for the API.

Snyder1977 commented 9 years ago

Hi all, I have the same problem as pimok. My Panasonic TV can be turned on but it chooses the wrong input. It will be set to the correct input, if I send the following command via shell: echo "tx 4f 82 23 00" | cec-client -s

I´d like to be able to set the active source via python. It would be great to have a python wrapper for setting the active source!

ghost commented 7 years ago

The cec-client utility has an "as" command which sets the Pi (or whatever device has the CEC adapter) as the active source. I'd at least like a wrapper for this.

s-gopinath commented 7 years ago

Hi Voltagex,

I tried the "as" command. But It always activate the HDMI1 source. But My the HDMI CEC adapter is connected to HDMI2. Can anyone tell me how to activate the HDMI port of which my device is connected?

trainman419 commented 6 years ago

set_active_source and get_active_source have now been implemented.

albfan commented 4 months ago

As this is based on libcec if https://github.com/Pulse-Eight/libcec/issues/656 is correct, will set_active_source really work? or only for hdmi1?

cec.transmit(destination, opcode, bytes([0x30,0x00]))

just work, but

cec.set_active_source(3)

always redirect to hdmi1