Add more features to pjlink integration

Can we add the ability to pull more info from the pjlink integration for projectors. My understanding is that it uses the pypjlink python script which has the ability to pull lamp and errors from a projector. Not just power or changing the source. I was using a custom script to do just this but seeing as this is a integration why not just add the support for those features.

The pjlink integration has no code owner. So someone would need to step up. They’d probably need to set up gui config and modernize the code to get it past a PR.

It is currently set up as a media player, and I don’t think media players in ha know about bulbs and errors. Those would have to be added as sensors, switches or whatever is appropriate.

Also it relies on pypjlink2. Can you get what you want from pypjlink2? If not, it has to be added there first.

Yes it looks like pypjlink2 python script does have refrences to lamps and errors in the code… Im not savvy on how it all works im just dangerous enough to be able to run the script and get some info back if i manually run it on my pc with python so i know i can poll that data so im assuming if I can homeassistant can too. Here is the projector.py code if anyone is curious and knows how to do this.

Just wanted to see if this can be looked at to add functionality to PJLINK.

Here is the cli.py file I was using to poll data from the projector on lamps and errors before something changed with commad_line integration. Now it no longer works and I get a generic error. Might be something to do with the version of python the script is made to run one im not sure. I dont know enough about python to be able to rewrite or submit this as a update to the custom integration.

import argparse

try:
    from ConfigParser import (
        NoSectionError,
        SafeConfigParser as ConfigParser
    )
except ImportError:
    from configparser import (
        NoSectionError,
        SafeConfigParser as ConfigParser
    )

from getpass import getpass
from os import path
import sys

import appdirs

from pypjlink import Projector
from pypjlink import projector
from pypjlink.cliutils import make_command, print_error

def cmd_power(p, state=None):
    if state is None:
        print(p.get_power())
    else:
        p.set_power(state)

def cmd_input(p, source, number):
    if source is None:
        source, number = p.get_input()
        print(source, number)
    else:
        p.set_input(source, number)

def cmd_inputs(p):
    for source, number in p.get_inputs():
        print('%s-%s' % (source, number))

def cmd_mute_state(p):
    video, audio = p.get_mute()
    print('video:', 'muted' if video else 'unmuted')
    print('audio:', 'muted' if audio else 'unmuted')

def cmd_mute(p, what):
    if what is None:
        return cmd_mute_state(p)
    what = {
        'video': projector.MUTE_VIDEO,
        'audio': projector.MUTE_AUDIO,
        'all': projector.MUTE_VIDEO | projector.MUTE_AUDIO,
    }[what]
    p.set_mute(what, True)

def cmd_unmute(p, what):
    if what is None:
        return cmd_mute_state(p)
    what = {
        'video': projector.MUTE_VIDEO,
        'audio': projector.MUTE_AUDIO,
        'all': projector.MUTE_VIDEO | projector.MUTE_AUDIO,
    }[what]
    p.set_mute(what, False)

def cmd_info(p):
    info = [
        ('Name', p.get_name()),
        ('Manufacturer', p.get_manufacturer()),
        ('Product Name', p.get_product_name()),
        ('Other Info', p.get_other_info())
    ]
    for key, value in info:
        print('%s: %s' % (key, value))

def cmd_lamps(p):
    for i, (time, state) in enumerate(p.get_lamps(), 1):
        print('Lamp %d: %s (%d hours)' % (
            i,
            'on' if state else 'off',
            time,
        ))

def cmd_errors(p):
    for what, state in p.get_errors().items():
        print('%s: %s' % (what, state))

def make_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('-p', '--projector')
    parser.add_argument('-e', '--encoding', default='utf-8')

    sub = parser.add_subparsers(dest='command', title='command')
    sub.required = True

    power = make_command(sub, 'power', cmd_power)
    power.add_argument('state', nargs='?', choices=('on', 'off'))

    inpt = make_command(sub, 'input', cmd_input)
    inpt.add_argument('source', nargs='?', choices=projector.SOURCE_TYPES)
    inpt.add_argument('number', nargs='?', choices='123456789', default='1')

    make_command(sub, 'inputs', cmd_inputs)

    mute = make_command(sub, 'mute', cmd_mute)
    mute.add_argument('what', nargs='?', choices=('video', 'audio', 'all'))

    unmute = make_command(sub, 'unmute', cmd_unmute)
    unmute.add_argument('what', nargs='?', choices=('video', 'audio', 'all'))

    make_command(sub, 'info', cmd_info)
    make_command(sub, 'lamps', cmd_lamps)
    make_command(sub, 'errors', cmd_errors)

    return parser

def resolve_projector(projector):
    password = None

    # host:port
    if projector is not None and ':' in projector:
        host, port = projector.rsplit(':', 1)
        port = int(port)

    # maybe defined in config
    else:
        appdir = appdirs.user_data_dir('pjlink')
        conf_file = path.join(appdir, 'pjlink.conf')

        try:
            config = ConfigParser({'port': '4352', 'password': ''})
            with open(conf_file, 'r') as f:
                config.readfp(f)

            section = projector
            if projector is None:
                section = 'default'

            host = config.get(section, 'host')
            port = config.getint(section, 'port')
            password = config.get(section, 'password') or None

        except (NoSectionError, IOError):
            if projector is None:
                raise KeyError('No default projector defined in %s' % conf_file)

            # no config file, or no projector defined for this host
            # thus, treat the projector as a hostname w/o port
            host = projector
            port = 4352


    return host, port, password

def main():
    parser = make_parser()
    args = parser.parse_args()

    kwargs = dict(args._get_kwargs())
    func = kwargs.pop('__func__')
    kwargs.pop('command', None)

    projector = kwargs.pop('projector')
    host, port, password = resolve_projector(projector)
    encoding = kwargs.pop('encoding')

    if not password:
        password = getpass

    with Projector.from_address(host, port, encoding) as proj:
        rv = proj.authenticate(password)
        if rv is False:
            print_error('Incorrect password.')
            return

        func(proj, **kwargs)

if __name__ == '__main__':
    main()

These are my errors… sorry if this is not the right place to post this but im not sure where else to do this…

Logger: homeassistant.components.command_line.utils
Source: components/command_line/utils.py:56
integration: Command Line (documentation, issues)
First occurred: 9:55:51 AM (67 occurrences)
Last logged: 10:11:21 AM

Command failed (with return code 1): python3 /config/python_scripts/pypjlink-1.2.1/pypjlink/cli.py '-p' '192.168.30.139' 'status'
Command failed (with return code 1): python3 /config/python_scripts/pypjlink-1.2.1/pypjlink/cli.py '-p' '192.168.30.139' 'power'
Command failed (with return code 1): python3 /config/python_scripts/pypjlink-1.2.1/pypjlink/cli.py '-p' '192.168.30.139' 'lamps'
Command failed (with return code 1): python3 /config/python_scripts/pypjlink-1.2.1/pypjlink/cli.py '-p' '192.168.30.139' 'errors'