Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made numpy requirement optional. Fixes #4 #5

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions aiopylgtv/constants.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import numpy as np
try:
import numpy as np
except ImportError:
np = None

CALIBRATION_TYPE_MAP = {
"uint8": "unsigned char",
"uint16": "unsigned integer16",
"float32": "float",
}
DEFAULT_CAL_DATA = np.array(
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0044, -0.0453, 1.041], dtype=np.float32
)

if np:
DEFAULT_CAL_DATA = np.array(
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0044, -0.0453, 1.041], dtype=np.float32
)
else:
DEFAULT_CAL_DATA = None

# xr, yr, xg, yg, xb, yb, xw, yw
BT2020_PRIMARIES = (0.708, 0.292, 0.170, 0.797, 0.131, 0.046, 0.3127, 0.3290)
DV_CONFIG_FILENAMES = {
Expand Down
11 changes: 10 additions & 1 deletion aiopylgtv/lut_tools.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import numpy as np
try:
import numpy as np
except ImportError:
np = None

from .constants import BT2020_PRIMARIES, DV_CONFIG_FILENAMES


def unity_lut_1d():
assert np # numpy needs to be installed for this feature
lutmono = np.linspace(0.0, 32767.0, 1024, dtype=np.float64)
lut = np.stack([lutmono] * 3, axis=0)
lut = np.rint(lut).astype(np.uint16)
return lut


def unity_lut_3d(n=33):
assert np # numpy needs to be installed for this feature
spacing = complex(0, n)
endpoint = 4096.0
lut = np.mgrid[0.0:endpoint:spacing, 0.0:endpoint:spacing, 0.0:endpoint:spacing]
Expand All @@ -22,6 +27,7 @@ def unity_lut_3d(n=33):


def read_cube_file(filename): # noqa: C901
assert np # numpy needs to be installed for this feature
nheader = 0
lut_1d_size = None
lut_3d_size = None
Expand Down Expand Up @@ -119,6 +125,7 @@ def lut_size(splitline, dim):


def read_cal_file(filename):
assert np # numpy needs to be installed for this feature
with open(filename, "r") as f:
caldata = f.readlines()

Expand Down Expand Up @@ -153,6 +160,7 @@ def read_cal_file(filename):


def lms2rgb_matrix(primaries=BT2020_PRIMARIES):
assert np # numpy needs to be installed for this feature

xy = np.array(primaries, dtype=np.float64)

Expand Down Expand Up @@ -192,6 +200,7 @@ def create_dolby_vision_config(
gamma=2.2,
primaries=BT2020_PRIMARIES,
):
assert np # numpy needs to be installed for this feature

if not (white_level >= 100.0 and white_level <= 999.0):
raise ValueError(
Expand Down
43 changes: 36 additions & 7 deletions aiopylgtv/webos_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import logging
import os

import numpy as np
import websockets
from sqlitedict import SqliteDict

Expand All @@ -23,6 +22,12 @@
unity_lut_3d,
)

try:
import numpy as np
except ImportError:
np = None


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -1064,6 +1069,7 @@ async def number_button(self, num):
await self.button(f"""{num}""")

def validateCalibrationData(self, data, shape, dtype):
assert np # numpy needs to be installed for this feature
if not isinstance(data, np.ndarray):
raise TypeError(f"data must be of type ndarray but is instead {type(data)}")
if data.shape != shape:
Expand All @@ -1076,6 +1082,7 @@ def validateCalibrationData(self, data, shape, dtype):
)

async def calibration_request(self, command, picMode, data):
assert np # numpy needs to be installed for this feature
dataenc = base64.b64encode(data.tobytes()).decode()

payload = {
Expand All @@ -1093,14 +1100,17 @@ async def calibration_request(self, command, picMode, data):
return await self.request(ep.CALIBRATION, payload)

async def start_calibration(self, picMode, data=DEFAULT_CAL_DATA):
assert np # numpy needs to be installed for this feature
self.validateCalibrationData(data, (9,), np.float32)
return await self.calibration_request(cal.CAL_START, picMode, data)

async def end_calibration(self, picMode, data=DEFAULT_CAL_DATA):
assert np # numpy needs to be installed for this feature
self.validateCalibrationData(data, (9,), np.float32)
return await self.calibration_request(cal.CAL_END, picMode, data)

async def upload_1d_lut(self, picMode, data=None):
assert np # numpy needs to be installed for this feature
info = self.calibration_support_info()
if not info["lut1d"]:
model = self._system_info["modelName"]
Expand All @@ -1113,6 +1123,7 @@ async def upload_1d_lut(self, picMode, data=None):
return await self.calibration_request(cal.UPLOAD_1D_LUT, picMode, data)

async def upload_3d_lut(self, command, picMode, data):
assert np # numpy needs to be installed for this feature
if command not in [cal.UPLOAD_3D_LUT_BT709, cal.UPLOAD_3D_LUT_BT2020]:
raise PyLGTVCmdException(f"Invalid 3D LUT Upload command {command}.")
info = self.calibration_support_info()
Expand All @@ -1131,57 +1142,69 @@ async def upload_3d_lut(self, command, picMode, data):
return await self.calibration_request(command, picMode, data)

async def upload_3d_lut_bt709(self, picMode, data=None):
assert np # numpy needs to be installed for this feature
return await self.upload_3d_lut(cal.UPLOAD_3D_LUT_BT709, picMode, data)

async def upload_3d_lut_bt2020(self, picMode, data=None):
assert np # numpy needs to be installed for this feature
return await self.upload_3d_lut(cal.UPLOAD_3D_LUT_BT2020, picMode, data)

async def set_ui_data(self, command, picMode, value):
assert np # numpy needs to be installed for this feature
if not (value >= 0 and value <= 100):
raise ValueError

data = np.array(value, dtype=np.uint16)
return await self.calibration_request(command, picMode, data)

async def set_brightness(self, picMode, value):
assert np # numpy needs to be installed for this feature
return await self.set_ui_data(cal.BRIGHTNESS_UI_DATA, picMode, value)

async def set_contrast(self, picMode, value):
assert np # numpy needs to be installed for this feature
return await self.set_ui_data(cal.CONTRAST_UI_DATA, picMode, value)

async def set_oled_light(self, picMode, value):
assert np # numpy needs to be installed for this feature
return await self.set_ui_data(cal.BACKLIGHT_UI_DATA, picMode, value)

async def set_color(self, picMode, value):
assert np # numpy needs to be installed for this feature
return await self.set_ui_data(cal.COLOR_UI_DATA, picMode, value)

async def set_1d_2_2_en(self, picMode, value=0):
assert np # numpy needs to be installed for this feature
data = np.array(value, dtype=np.uint16)
return await self.calibration_request(
cal.ENABLE_GAMMA_2_2_TRANSFORM, picMode, data
)

async def set_1d_0_45_en(self, picMode, value=0):
assert np # numpy needs to be installed for this feature
data = np.array(value, dtype=np.uint16)
return await self.calibration_request(
cal.ENABLE_GAMMA_0_45_TRANSFORM, picMode, data
)

async def set_bt709_3by3_gamut_data(
self, picMode, data=np.identity(3, dtype=np.float32)
):
async def set_bt709_3by3_gamut_data(self, picMode, data=None):
assert np # numpy needs to be installed for this feature
if data is None:
data = np.identity(3, dtype=np.float32)
self.validateCalibrationData(data, (3, 3), np.float32)
return await self.calibration_request(cal.BT709_3BY3_GAMUT_DATA, picMode, data)

async def set_bt2020_3by3_gamut_data(
self, picMode, data=np.identity(3, dtype=np.float32)
):
async def set_bt2020_3by3_gamut_data(self, picMode, data=None):
assert np # numpy needs to be installed for this feature
if data is None:
data = np.identity(3, dtype=np.float32)
self.validateCalibrationData(data, (3, 3), np.float32)
return await self.calibration_request(cal.BT2020_3BY3_GAMUT_DATA, picMode, data)

async def set_dolby_vision_config_data(
self, white_level=700.0, black_level=0.0, gamma=2.2, primaries=BT2020_PRIMARIES
):
assert np # numpy needs to be installed for this feature

info = self.calibration_support_info()
dv_config_type = info["dv_config_type"]
Expand Down Expand Up @@ -1219,6 +1242,7 @@ async def set_tonemap_params(
mastering_peak_3=10000,
rolloff_point_3=50,
):
assert np # numpy needs to be installed for this feature

data = np.array(
[
Expand All @@ -1236,6 +1260,7 @@ async def set_tonemap_params(
return await self.calibration_request(cal.SET_TONEMAP_PARAM, picMode, data)

async def ddc_reset(self, picMode, reset_1d_lut=True):
assert np # numpy needs to be installed for this feature
if not isinstance(reset_1d_lut, bool):
raise TypeError(
f"reset_1d_lut should be a bool, instead got {reset_1d_lut} of type {type(reset_1d_lut)}."
Expand All @@ -1260,6 +1285,7 @@ async def get_picture_settings(
return ret["settings"]

async def upload_1d_lut_from_file(self, picMode, filename):
assert np # numpy needs to be installed for this feature
ext = filename.split(".")[-1].lower()
if ext == "cal":
lut = await asyncio.get_running_loop().run_in_executor(
Expand All @@ -1277,6 +1303,7 @@ async def upload_1d_lut_from_file(self, picMode, filename):
return await self.upload_1d_lut(picMode, lut)

async def upload_3d_lut_from_file(self, command, picMode, filename):
assert np # numpy needs to be installed for this feature
ext = filename.split(".")[-1].lower()
if ext == "cube":
lut = await asyncio.get_running_loop().run_in_executor(
Expand All @@ -1290,11 +1317,13 @@ async def upload_3d_lut_from_file(self, command, picMode, filename):
return await self.upload_3d_lut(command, picMode, lut)

async def upload_3d_lut_bt709_from_file(self, picMode, filename):
assert np # numpy needs to be installed for this feature
return await self.upload_3d_lut_from_file(
cal.UPLOAD_3D_LUT_BT709, picMode, filename
)

async def upload_3d_lut_bt2020_from_file(self, picMode, filename):
assert np # numpy needs to be installed for this feature
return await self.upload_3d_lut_from_file(
cal.UPLOAD_3D_LUT_BT2020, picMode, filename
)
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
setup(
name="aiopylgtv",
packages=["aiopylgtv"],
install_requires=["websockets>=8.1", "numpy>=1.17.0", "sqlitedict"],
install_requires=["websockets>=8.1", "sqlitedict"],
extras_require={"calibration": ["numpy>=1.17.0"]},
python_requires=">=3.7",
zip_safe=True,
version="0.3.2",
Expand Down