Skip to content

Instantly share code, notes, and snippets.

@evadne
Last active December 31, 2022 20:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evadne/4a1ec282c661178ac8158744b4260e00 to your computer and use it in GitHub Desktop.
Save evadne/4a1ec282c661178ac8158744b4260e00 to your computer and use it in GitHub Desktop.
NEC X651UHD External Control
#!/usr/bin/env python3
import select
import socket
import sys
import functools
import datetime
import time
class Display:
def __init__(self, host, port):
self.host = host
self.port = port
self.timeout = 5
def send(self, buffer):
display_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
display_socket.settimeout(self.timeout)
display_socket.connect((self.host, self.port))
display_socket.setblocking(self.timeout)
display_socket.sendall(buffer)
if select.select([display_socket], [], [], self.timeout)[0]:
data = display_socket.recv(512)
display_socket.close()
return data
else:
raise Exception("timeout")
def parse_response(self, buffer):
length = int(buffer[5:7].decode(), 16)
envelope = buffer[7:-2]
if len(envelope) == length:
if envelope[:1] == bytes([0x02]):
if envelope[-1:] == bytes([0x03]):
if self.compute_checksum(buffer[1:(7+length)]) == buffer[-2:-1]:
return envelope[1:-1]
raise Exception("incomplete_response")
def encode_message(self, type, message):
content = bytes([0x01, 0x30]) + b'*0' + type + "{:02x}".format(2 + int(len(message))).upper().encode() + bytes([0x02]) + message + bytes([0x03])
checksum = self.compute_checksum(content[1:])
return content + checksum + bytes([0x0D])
def compute_checksum(self, buffer):
return bytes([functools.reduce(lambda a, b: a ^ b, list(buffer))])
def send_command(self, command):
response_envelope = self.send(self.encode_message(b'A', command))
return self.parse_response(response_envelope)
def get_parameter(self, opcode_page, opcode):
response_envelope = self.send(self.encode_message(b'C', opcode_page + opcode))
response = self.parse_response(response_envelope)
assert 16 == len(response)
assert opcode_page == response[2:4]
assert opcode == response[4:6]
if b'00' == response[0:2]:
max = int(response[8:12], 16)
current = int(response[12:16], 16)
if b'00' == response[6:8]:
return dict(success = True, type = 'fixed', max = max, current = current)
if b'01' == response[6:8]:
return dict(success = True, type = 'automatic', max = max, current = current)
if b'01' == response[0:2]:
return dict(success = False)
raise Exception('invalid_response')
def set_parameter(self, opcode_page, opcode, value):
request_value = "{:04x}".format(int(value)).upper().encode()
request_message = opcode_page + opcode + request_value
request = self.encode_message(b'E', request_message)
response_envelope = self.send(request)
response = self.parse_response(response_envelope)
assert 16 == len(response)
assert opcode_page == response[2:4]
assert opcode == response[4:6]
if b'00' == response[0:2]:
max = int(response[8:12], 16)
requested = int(response[12:16], 16)
if b'00' == response[6:8]:
return dict(success = True, type = 'fixed', max = max, requested = requested)
if b'01' == response[6:8]:
return dict(success = True, type = 'automatic', max = max, requested = requested)
if b'01' == response[0:2]:
return dict(success = False)
raise Exception('invalid_response')
class Handler:
def __init__(self, display):
self.display = display
def get_power_status(self):
result = self.display.send_command(b'01D6')
if result == b'0200D60000040001':
print('on')
elif result == b'0200D60000040002':
print('power_save_standby')
elif result == b'0200D60000040003':
print('power_save_suspend')
elif result == b'0200D60000040004':
print('off')
else:
raise Exception('bad_response')
def get_image_contrast(self):
result = self.display.get_parameter(b'00', b'12')
assert result['success']
print(result['current'])
def get_image_brightness(self):
result = self.display.get_parameter(b'00', b'92')
assert result['success']
print(result['current'])
def get_image_sharpness(self):
result = self.display.get_parameter(b'00', b'8C')
assert result['success']
print(result['current'])
def get_colour_temperature(self):
result = self.display.get_parameter(b'00', b'54')
assert result['success']
print(2600 + 100 * result['current'])
def get_backlight(self):
result = self.display.get_parameter(b'00', b'10')
assert result['success']
print(result['current'])
def get_temperature(self):
result = self.display.get_parameter(b'02', b'79')
current = result['current']
assert result['success']
if current > (1 << 8):
print(-1 * (((~(current - 1)) & ((1 << 8) - 1)) / 2))
else:
print(current / 2)
def turn_on(self):
result = self.display.send_command(b'C203D6001')
assert result == b'00C203D6001'
print("ok")
def turn_off(self):
result = self.display.send_command(b'C203D6004')
assert result == b'00C203D6004'
print("ok")
def set_datetime(self):
local_time = time.localtime()
year = "{:02x}".format(int(local_time.tm_year - 2000)).upper().encode()
mon = "{:02x}".format(int(local_time.tm_mon)).upper().encode()
mday = "{:02x}".format(int(local_time.tm_mday)).upper().encode()
wday = "{:02x}".format(int((local_time.tm_wday + 1) % 7)).upper().encode()
hour = "{:02x}".format(int(local_time.tm_hour)).upper().encode()
min = "{:02x}".format(int(local_time.tm_min)).upper().encode()
dst = "{:02x}".format(int(local_time.tm_isdst)).upper().encode()
value = year + mon + mday + wday + hour + min + dst
command = b'C212' + value
result = self.display.send_command(command)
assert b'C312' == result[:4]
assert b'00' == result[4:6]
assert value == result[6:24]
print("ok")
def set_image_contrast(self, value):
result = self.display.set_parameter(b'00', b'12', int(value))
assert result['success']
print('ok')
def set_image_brightness(self, value):
result = self.display.set_parameter(b'00', b'92', int(value))
assert result['success']
print('ok')
def set_image_sharpness(self, value):
result = self.display.set_parameter(b'00', b'8C', int(value))
assert result['success']
print('ok')
def set_colour_temperature(self, value):
value = int(value)
assert value >= 2600
assert value <= 10000
result = self.display.set_parameter(b'00', b'54', int((value - 2600) / 100))
assert result['success']
print('ok')
def set_backlight(self, value):
result = self.display.set_parameter(b'00', b'10', int(value))
assert result['success']
print('ok')
def set_temperature_sensor_index(self, value):
result = self.display.set_parameter(b'02', b'78', int(value))
assert result['success']
print('ok')
def handle_command(self, command, arguments):
try:
getattr(self, command)(*arguments)
except:
raise Exception("bad_command")
display = Display(sys.argv[1], 7142)
handler = Handler(display).handle_command(sys.argv[2], sys.argv[3:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment