Git Product home page Git Product logo

jvc_projector's Introduction

JVC Projector Remote

A python package to control JVC Projectors over IP.

⚠️ This project is looking for (co-)maintainers. Times change, I might end up with a different projector brand, JVC might change the command interface for a newer model that I don't have. Enough people use this library now that I think it's important to think about think about its future. I would be grateful to have people who are competent in python and have access to a JVC projector on board. If you're willing to help, submit a pull request implementing new features, fixing bugs or tidying up my terrible programming and documentation!

If you'd like to make a donation to sponsor work on this project, you can donate on ko-fi, or github sponsors

References

This library is used by following software:

It can also be used standalone or in a Python script.

Command format

Read state

To read a property, use the JVCProjector.command(<command>) method.

Examples:

  • Power state: send command power and the response will be standby, lamp_on, cooling, reserved or emergency
  • Signal state: send command signal and the response will be no_signal or active_signal

Write state

To control the projector, use JVCProjector.command(<command>-<state>).

Examples:

  • Power ON: power-on
  • Change picture mode to film: picture_mode-film
  • Switch lamp to high: lamp-high

Supported commands

Description Command State
Power power Read: standby, lamp_on, cooling, reserved, emergency
Write: on, off
Lens Memory memory Read/Write: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Input input Read/Write: hdmi1, hdmi2
Picture Mode picture_mode film, cinema, natural, hdr10, thx, user1, user2, user3, user4, user5, user6, hlg, frame_adapt_hdr, hdr10p, pana_pq
Low Latency Mode low_latency Read/Write: on, off
Mask mask Read/Write: off, custom1, custom2, custom3
Lamp Setting lamp high, low, mid
Menu Buttons menu Write: menu, down, left, right, up, ok, back
Lens Aperture aperture Read/Write: off, auto1, auto2
Anamorphic Mode anamorphic Read/Write: off, a, b, c, d
Signal Status signal Read: no_signal, active_signal
Get Mac Address macaddr Read: returns mac address string
Model Info modelinfo Read: returns the model info string
Test Connection null Write: no write payload, used for testing connection

NOTE: Not all commands or states are supported by all models. You can easily tell by testing them on your JVC projector.

Installation

For the latest stable version,

$ python3 -m pip install jvc_projector_remote

If you want to install the latest unstable commits from this repo,

$ python3 -m pip install -e git+https://github.com/bezmi/jvc_projector.git#egg=jvc-projector-remote

Building from source

If you've made changes and want to install them, ensure you have hatch.

$ python3 -m pip install hatch

Run the build command from the root directory of this repository.

$ hatch build

Finally, you can install the package. Make sure the filename that you specify matches the one you want to install in the dist/ directory.

$ pip install dist/jvc_projector_remote-vX.X.X-py3-none-any.whl

The --force-reinstall flag will ensure that updated files are installed even if the version number of your build matches the pre-existing package.

Usage

For usage with Home Assistant, see here.

Below is an example for using this module standalone (see command format section for command strings):

>>> from jvc_projector_remote import JVCProjector

 # replace with your projector's local IP
>>> host = "192.168.1.12"

# initialise (for models older than the NZ series)
>>> projector = JVCProjector(host, port=20554, delay_ms=600, connect_timeout=10, max_retries=10)

# initialise (alternate, with network password)
>>> projector = JVCProjector(host, password="MYPASSWORD", port=20554, delay_ms=600, connect_timeout=10, max_retries=10)

# power on, power off
>>> projector.power_on()
# check status once it's on
>>> projector.is_on()
True

>>> projector.power_off()
# check if it's off
>>> projector.is_on()
False

# Send arbitrary command
# see the command format section above
>>> projector.command("input-hdmi2")

Confirmed models

This module is confirmed to work for the models listed below. It should also work with projectors in the same series as the ones listed.

  • DLA-X5900
  • NX5
  • NZ8/RS3100
  • DLA-RS440

If you've confirmed functionality with a model that is unlisted, raise an issue or submit a pull request to have it added.

Adding new commands

Raise an issue or open a pull request. Add new commands to the Commands class. The format is documented in the docstring for the parent Command class.

jvc_projector's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

jvc_projector's Issues

How to add commands to hass_custom_components

Hello,

I have the custom integration successfully added to HASS and configured the remote in the home assistant configuration.yaml, with my projector's ip address. This all works fine, I used the services tool, in the developer tools to turn on the projecter and change the profile to cinema. Super cool, and thank you for building this.

I'm now trying to add commands for switching between the Custom Mask settings (I have a scope screen and would like to mask the top and bottom of the screen when zoomed out, I'd like to turn off the mask when zoomed in for non scope content.)

I found these "IP codes" on AVS: (https://www.avsforum.com/threads/official-jvc-20ltd-rs640-x990-x9900-rs540-x790-x7900-owners-thread.2923938/post-60433741)

[Mask Off: 0x21, 0x89, 0x01, 0x49, 0x53, 0x4D, 0x41, 0x32, 0x0A
Mask Custom1: 0x21, 0x89, 0x01, 0x49, 0x53, 0x4D, 0x41, 0x30, 0x0A
Mask Custom2: 0x21, 0x89, 0x01, 0x49, 0x53, 0x4D, 0x41, 0x31, 0x0A
Mask Custom3: 0x21, 0x89, 0x01, 0x49, 0x53, 0x4D, 0x41, 0x33, 0x0A]

I realize you provided instructions on how to add commands, and I think I understand how to do that. However, I don't know WHERE and in what file to add those commands when using the hass_custom_components integration. The file located in the non HASS repo at https://github.com/bezmi/jvc_projector/blob/master/jvc_projector/__init__.py has lines like:

class Commands(Enum):
# power commands
power_on = b"\x21\x89\x01\x50\x57\x31\x0A"

I tried adding the following lines to /config/custom_components/jvcprojector/init.py and restarting home assistant, but then the projector remote does not show up in home assistant anymore, so obviously I'm doing something wrong.

class Commands(Enum):
# mask commands
mask_off = b"\x21\x89\x01\x49\x53\x4D\x41\x32\x0A"
mask_custom1 = b"\x21\x89\x01\x49\x53\x4D\x41\x30\x0A"
mask_custom2 = b"\x21\x89\x01\x49\x53\x4D\x41\x31\x0A"
mask_custom3 = b"\x21\x89\x01\x49\x53\x4D\x41\x33\x0A"

Could you please provide me a little guidance on how and where to add these additional commands for use in home assistant?

Thanks in advance!

HDR/Cinema/etc buttons

Hi good sir,
Thanks for making this!
Any chance you could consider adding support for switching between Cinema and HDR (and that third button on the remote which I seldom use)?

New set of Commands to be added

Hi,

I am looking for the cursor commands to navigate in the menu via external commands, I do not see it in the documentation, anyone knows these?

LEFT
RIGHT
UP
DOWN
OK
BACK

power on command timing

Hi,

I tried your code with JVC DLA-X30B.

All worked accept the Power On command. After some debugging, I inserted 1 second delay after sending the power on command and I had to send 3 of these in a row from my script. WIth that, all finally worked. I have 4 separate scripts that work on the same code that you provide + my delay after the sendall command of 1 second. The 3 scripts of power off, status, and model inquiry work as is. The power on command works only if I send it 3 times in a row. I would hope to figure out what the timing issue is but may need your help.

Refactoring command function to make result handling and exception handling easier

In the HomeAssistant code I have to catch exceptions every location a command is called. Right now that is due to the calling of either command() or power_state().

They both trigger _send_command() but in a different way.

I wanted to refactor the command() so it can handle both commands that do return results or commands that don't return results:

A basic version was working, but it meant changing a lot of the basics and it felt like I was adding spaghetti-code and magic behaviour.

In essence I altered command() to check if the provided command_string was a ResultCommand or a Command. In case of a ResultCommand it needs an ack, which required knowing which ack to receive. For power state this is easy and with a minor change using the ACKs enum to get the ack based on the command string was possible. However imput changes are variable, but the ack the same. So that would mean introducing multiple ACKs with same command like so:

class ACKs(Enum):
    power_status = b"\x06\x89\x01\x50\x57\x0A"
    hdmi1 = b"\x06\x89\x01\x49\x50\x0A"
    hdmi2 = b"\x06\x89\x01\x49\x50\x0A"

It worked okay-ish. But after the comand was sent, the result must be handled and stored. I didn't want to alther the return True/False on command so extendend it to save the message, which could then be processed in a helper function for that power status. I ended in finding if a _translate_<command>() function-ish situation which did work. But as said, it felt spaghetti-code like.

The command looked something like this:

    def command(self, command_string, receive=False):
        print(command_string)

        if hasattr(Commands, command_string):
            self._send_command(Commands[command_string].value)
            return True

        if hasattr(ResultCommands, command_string):

            result_message = self._send_command(ResultCommands[command_string].value, ack=ACKs[command_string].value)
            if hasattr(self, '_translate_' + command_string) and callable(getattr(self, '_translate_' + command_string)):
                self.result_message = getattr(self, '_translate_' + command_string)(result_message)

            return True

        return False

Right now it feels like there is an extra layer of information is required which maps commands to results or a way of interpreting results. Maybe a grouping of certain commands and its generic handling (like that input command results should be handled the same) and that certain commands are ACK-ed the same.

If this is refactored, adding of the commands (which sroelens asked about in #4) is then possible.

Food for thought!

Keep connection alive after JVC handshake for multiple commands

Playing around with a serial console and direct connection to the projector, it's apparent that multiple commands can be sent after the JVC handshake procedure. Currently, we close the socket after a command is sent and re-connect via the handshake for the next clmmand.

The code should be refactored to keep the connection alive. It will improve reliability.

Version Key Required

To prevent future HA upgrades from breaking this great component, can you add the version as shown in the error below?

PS: Thanks for creating this. Absolutely fantastic!

No 'version' key in the manifest file for custom integration 'jvcprojector'. This will not be allowed in a future version of Home Assistant. Please report this to the maintainer of 'jvcprojector'
11:54:58 AM – loader.py (WARNING)

Timeout error on handshake

I've been trying to connect to my JVC LX-NZ30 projector via Home Assistant. I've tried the HA included integration and the custom integration that uses this in the backend and both fail to connect.

I traced down here from the custom integration and tried running this module direct from Python. The result is a connection failure based on a handshake timeout.

I've seen other mention of this handshake protocol on the web but the LX-NZ30 doesn't seem to require/support it. I've managed to successfully control my projector with as little as this:

import socket
import binascii

host = '192.168.1.19'
port = 4661

ctrl_power_on = b'\x06\x14\x00\x04\x00\x34\x11\x00\x00\x5D'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.send(ctrl_power_on)

received_data = s.recv(1024)
print (binascii.hexlify(received_data))

I don't do any handshake, at least on the surface. Maybe socket is doing something generic under the hood. I'm wondering if there's a way to make the handshake conditional or base it off of the projector model number.

Import error on jvccommands.py L40 - TypeError: 'type' object is not subscriptable

$ root@homebridge:/var/lib/homebridge $ python3 --version
Python 3.8.10
from jvc_projector_remote import JVCProjector
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/jvc_projector_remote/__init__.py", line 1, in <module>
    from .jvcprojector import *
  File "/usr/local/lib/python3.8/dist-packages/jvc_projector_remote/jvcprojector.py", line 7, in <module>
    from .jvccommands import *
  File "/usr/local/lib/python3.8/dist-packages/jvc_projector_remote/jvccommands.py", line 19, in <module>
    class Command:
  File "/usr/local/lib/python3.8/dist-packages/jvc_projector_remote/jvccommands.py", line 40, in Command
    readwritevals: tuple[dict[str, bytes]] = field(repr=False)
TypeError: 'type' object is not subscriptable

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.