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

WideQ from ha-smartthinq-sensor component #100

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

ollo69
Copy link

@ollo69 ollo69 commented May 28, 2020

So let's start comparing the code with this PR

Copy link
Owner

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting this started!

The way I would love to start this off would be by changing out the core layer to use the v2 API instead of the v1 API, and probably changing the client layer to do the same. So maybe a good way to move forward with that would be to change your v2 implementation to overwrite the old v1 implementation, and to use names as if it were going to be the only implementation. That is, no need to put 2s everywhere—just use the same name. Then we can go through the changes and try to find the minimum set of changes that are actually required to support the new API—and not focus on the parts of the code that haven't had to change.

wideq/core.py Outdated


def oauth2_signature(message: str, secret: str) -> bytes:
def oauth2_signature(message, secret):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's an example of a change we can just revert back to the current version (since it seems to be newer).

wideq/core.py Outdated
secret_bytes = secret.encode('utf8')
hashed = hmac.new(secret_bytes, message.encode('utf8'), hashlib.sha1)
secret_bytes = secret.encode("utf8")
hashed = hmac.new(secret_bytes, message.encode("utf8"), hashlib.sha1)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's an example of a change we can omit because it's just cosmetic (and it would be great to focus on the substantive changes).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was changed by black formatting. If it's really a problem I can search all this change and replace, prefer not have to do :)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The quotes themselves are not really the problem, but the "diff noise" is because it makes it hard to review the changes. But no worries; I can do the find-and-replace.


class Tlsv1HttpAdapter(HTTPAdapter):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? I know some people get TLS errors when they use the wrong country server, but reverting to TLSv1 for all connections is a security concern. (Maybe we can leave this out for now and focus on other stuff first?)

Copy link
Author

@ollo69 ollo69 May 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more related to some country server that need this.
Probably some check should be done during connection to choose the right TLS method, otherwise for some user/region do not work

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great; that seems like a good idea. For this first iteration, let's leave stuff like this out and just focus on the minimal, core changes to support version 2 of the LG API.

wideq/core.py Outdated
@@ -188,49 +75,84 @@ def lgedm_post(url, data=None, access_token=None, session_id=None):
authenticated requests. They are not required, for example, to load
the gateway server data or to start a session.
"""

_LOGGER.debug("lgedm_post before: %s", url)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debugging stuff like this can probably be left out.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you implement a different type of logging, so maybe the log have to be reviewed?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, sounds good—let's leave that for a future pull request.

wideq/core_v2.py Outdated
):
"""Make an HTTP request in the format used by the API2 servers."""

# this code to avoid ssl error 'dh key too small'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this hack necessary for all connections, or is it just in some circumstances that we need this?

Copy link
Author

@ollo69 ollo69 May 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some circumstances, but as before the problem is to really understand when should be used

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, sounds good—but as with other tangential features discussed above, let's move carefully and just do one thing at a time, i.e., leave additional features like this to future pull requests so we can discuss them individually.

@ollo69
Copy link
Author

ollo69 commented May 30, 2020

So I removed CoreV1 and renamed CoreV2 to Core.
Client is still inside core module.

Copy link
Owner

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, great! Thanks for getting that started. As I mentioned above, I think it would be great to focus on one thing at a time, and the first thing to focus on is the core API changes. To that end, let's try to make this PR only contain changes to the low-level core API stuff and the higher-level "client" layer. Specifically, at a very high level of abstraction, let's do this:

  • Roll back the changes to __init__.py.
  • Restore util.py.
  • Move the client stuff back to client.py from core.py and device.py.
  • Move the exceptions back from core_exceptions.py to core.py.
  • Roll back the changes to all the device-specific files: dishwasher.py, dryer.py, refrigerator.py, and washer.py (and remove *_states.py). We'll address these changes in future PRs.

I'd be happy to help with these (I think GitHub lets me push to your branch because the PR is open) if that would be useful.

@ollo69
Copy link
Author

ollo69 commented May 30, 2020

Ok, I limited changes as you suggest.
Anyway consider that in this way is not possible to monitor ThinQ2 devices because they use a different method to update the status and do not require poll.
I changed the Device class to avoid polling device != ThinQ1
Not sure that merging in master branch is a good option, may be should be created a dedicated branch to merge in the future with master?

@sampsyo
Copy link
Owner

sampsyo commented May 30, 2020

OK, got it, cool. Yeah, maybe we should plan on merging this into a branch and then try to fix the monitoring stuff next—then everything can go into master, because presumably we'll have full parity with the old version?

Copy link
Owner

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a list of comments on differences to clean up in core (I haven't worked on client yet). Next I'll try taking care of some of the diff noise.

wideq/core.py Outdated
@@ -137,10 +152,16 @@ def __init__(self, code, message):
class NotLoggedInError(APIError):
"""The session is not valid or expired."""

def __init__(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not add these empty-argument constructors—it's actually good to keep around the error code and message!

wideq/core.py Outdated
@@ -169,68 +196,146 @@ def __init__(self, device_id, code):
self.code = code


API_ERRORS = {
API2_ERRORS = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this name back.

wideq/core.py Outdated
"0102": NotLoggedInError,
"0106": NotConnectedError,
"0100": FailedRequestError,
9000: InvalidRequestError, # Surprisingly, an integer (not a string).
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restore these errors.

"x-thinq-app-level": V2_APP_LEVEL,
"x-thinq-app-os": V2_APP_OS,
"x-thinq-app-type": V2_APP_TYPE,
"x-thinq-app-ver": V2_APP_VER,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all these headers really necessary? I think we should try pruning them down and see if the requests still work. (When I was original reverse-engineering the first version of the API, I found that the client included lots of headers that were not actually necessary to make the request work.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be not, not sure, require some test, may be after merging the code?

):
"""Make an HTTP request in the format used by the API2 servers."""

# this code to avoid ssl error 'dh key too small'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this special SSL stuff.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot remove, without this doesn't work with my country!!!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can also confirm that POST requests in the US don't work without forcing TLSv1. There may be something else going on, though, because I POST successfully but get back error code 0009.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, the error text accompanying code 0009 translates to "Device does not exist"
@ollo69, does lgedm2_post work for you?

self.gateway.country, self.gateway.language)
session_id = session_info['jsessionId']
return Session(self, session_id), get_list(session_info, 'item')
return Session(self)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm… in thinq2, is there no such thing as a "session"? Maybe we should add this to our list of things to clean up post-merge then… if there's no need to initiate sessions, there's no need for the Session class.

headers["x-emp-token"] = access_token

if user_number:
headers["x-user-no"] = user_number
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the user number really necessary to make the API work? A lot of things could be simplified if it could be omitted, and it seems strange that the API would need it in addition to the token.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is, I'm sure about this


class Session(object):
def __init__(self, auth, session_id) -> None:
def __init__(self, auth, session_id=None):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is session_id ever non-None in thinq2? If not, let's remove this parameter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to better check this

self.auth = auth
self.session_id = session_id

def post(self, path, data=None):
"""Make a POST request to the API server.
"""Make a POST request to the APIv1 server.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really for thinq1? If so, let's delete it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I said before, this is used, depend on the device

wideq/core.py Outdated

return get_list(self.post('device/deviceList'), 'item')
devices = self.get2("service/application/dashboard").get("item", [])
return as_list(devices)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason to use as_list here instead of the older get_list, which makes things easier to read?

Copy link
Owner

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleanup done; here are a few scattered comments on client as a bonus.

wideq/client.py Outdated

return client

def dump(self) -> Dict[str, Any]:
"""Serialize the client state."""

out: Dict[str, Any] = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restore this type annotation.

wideq/client.py Outdated
}

if self._gateway:
out['gateway'] = self._gateway.serialize()
out["gateway"] = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason why this no longer uses the serialize method?

wideq/client.py Outdated

if self._auth:
out['auth'] = self._auth.serialize()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

wideq/client.py Outdated

return out

def refresh(self) -> None:
self._auth = self.auth.refresh()
self._session, self._devices = self.auth.start_session()
self._session = self.auth.start_session()
# self._device = None
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete.

@ollo69
Copy link
Author

ollo69 commented Jun 2, 2020

Ok, sorry but on this days I was busy.
I start a first review and added some answer to your comment.
May be we can resolve old conversation and start with new review? Otherwise it becomes to be too mutch confusing....

wideq/client.py Outdated

# The last list of devices we got from the server. This is the
# raw JSON list data describing the devices.
self._devices: List[Dict[str, Any]] = []
self._devices = None
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change leads to the whole script crashing in case there is no device. Since we later assume _devices to be an interable.

  File "./example.py", line 33, in ls
    for device in client.devices:
  File "/home/frederik/dev/projects/home_automation/wideq/wideq/client.py", line 151, in devices
    return (DeviceInfo(d) for d in self._devices)
TypeError: 'NoneType' object is not iterable

}

@classmethod
def load(cls, gateway, data):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me this always fails, when the new wideq_state.json is written, it only contains "model_info", "gateway" and "auth" as keys.

Copy link

@ThatWileyGuy ThatWileyGuy Jul 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like Auth.serialize() in core.py needs to be redirected to Auth.dump(). One of them should probably be deleted since they're duplicates.


def serialize(self) -> Dict[str, str]:
return {
'access_token': self.access_token,
'refresh_token': self.refresh_token,
}

def dump(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted below, this function needs to be de-duped with serialize() just above.

LOGGER.debug("Injected debug device: %s", d)

def _load_devices(self, force_update: bool = False):
if self._session and (self._devices is None or force_update):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't work as-is for two reasons:

  • self._session is itself initialized lazily, so if that hasn't happened as a side effect of something else, we bail out. I suspect you really just want self.session instead to force the initialization to happen.
  • self._devices is initialized to [], which isn't None. I suspect you probably want to check not self._devices instead?

@ThatWileyGuy
Copy link

ThatWileyGuy commented Jul 11, 2020

So I'm prodding at this branch to try and get my portable AC working, and it looks like the model information has also changed?
Mine looks like this: https://gist.github.com/ThatWileyGuy/0ad9175fe9603e5751fedbc822021d5d
... and it's one of these: https://www.homedepot.com/p/LG-Electronics-14-000-BTU-10-000-BTU-DOE-Portable-Air-Conditioner-Dual-Inverter-Quiet-Energy-Eff-Wi-Fi-with-LCD-Remote-in-White-LP1419IVSM/307296364

... so I'm hacking away at ACDevice trying to get ac-config and set-temp to work and finding that I have to change the values it's referencing in the JSON.
Two questions that seem relevant here:

  • does someone have a copy of one of the V1 device information blobs that I can use for reference?
  • can we assume that all devices have V2 device information blobs such that once we move to API V2 we don't need the old code?

@SkOODaT
Copy link

SkOODaT commented Jul 12, 2020

id really like to see V2 implemented, Ive tried to get this working but its a bit beyond what i can do in python, seems like https://github.com/tinkerborg/thinq2-python/tree/dump-device can pull info tho and is semi working so its useful to get information, homebridge for homekit - https://github.com/sman591/homebridge-lg-thinq-ac works too for info and that has commands working, the data i was able to gather on my specific AC

@ThatWileyGuy we have the same unit just diff regions mines WW i believe

{'alias': 'AirConditioner',
'appModuleSize': 6082481,
'appModuleUri': 'APRIVATEURL',
'appModuleVer': 12.49,
'appRestartYn': 'Y',
'appType': 'NUTS',
'area': 55488,
'autoOrderYn': 'N',
'blackboxYn': 'Y',
'combinedProductYn': 'N',
'controllableYn': 'Y',
'countryCode': 'CA',
'curOffset': -4,
'curOffsetDisplay': '-04:00',
'deviceCode': 'AI01',
'deviceId': 'MYDEVICEID',
'deviceState': 'E',
'deviceType': 401,
'drServiceYn': 'N',
'dstOffset': -4,
'dstOffsetDisplay': '-04:00',
'fwInfoList': [{'checksum': '00005101',
                'order': 2.0,
                'partNumber': 'SAA40115101'},
               {'checksum': '0000045B',
                'order': 1.0,
                'partNumber': 'SAA40115201'}],
'fwVer': '',
'groupableYn': 'Y',
'guideType': 'POT_TYPE1',
'guideTypeYn': 'Y',
'imageFileName': 'ac_home_portable_airconditioner_img.png',
'imageUrl': 'APRIVATEURL',
'langPackProductTypeUri': 'APRIVATEURL',
'langPackProductTypeVer': 39.9,
'macAddress': 'MYMACADRESS',
'masterYn': 'Y',
'modelCountryCode': 'WW',
'modelJsonUri': 'APRIVATEURL',
'modelJsonVer': 10.52,
'modelName': 'POT_056905_WW',
'modelProtocol': 'STANDARD',
'modemInfo': {'appVersion': 'clip_hna_v1.9.045',
              'modelName': 'POT_056905_WW',
              'modemType': 'QCOM_QCA4010'},
'networkType': '02',
'newRegYn': 'N',
'online': True,
'order': 0,
'pccModelYn': 'N',
'platformType': 'thinq2',
'regDt': 20200526144811.0,
'regDtUtc': '20200526184811',
'remoteControlType': '',
'sdsGuide': '{"deviceCode":"AI01"}',
'sdsPid': {'sds1': '', 'sds2': '', 'sds3': '', 'sds4': ''},
'smallImageUrl': 'APRIVATEURL',
'snapshot': {'airState.diagCode': 0.0,
             'airState.energy.accumulated': 106.0,
             'airState.energy.accumulatedTime': 304.0,
             'airState.energy.onCurrent': 1405.0,
             'airState.filterMngStates.maxTime': 250.0,
             'airState.filterMngStates.useTime': 26.0,
             'airState.opMode': 0.0,
             'airState.operation': 1.0,
             'airState.quality.sensorMon': 0.0,
             'airState.reservation.sleepTime': 0.0,
             'airState.reservation.targetTimeToStart': 0.0,
             'airState.reservation.targetTimeToStop': 0.0,
             'airState.tempState.current': 27.0,
             'airState.tempState.target': 16.0,
             'airState.wDir.vStep': 100.0,
             'airState.windStrength': 6.0,
             'meta': {'allDeviceInfoUpdate': False,
                      'messageId': 'PSShgI2tQeS8Sk0H0yWBBg'},
             'mid': 137871566.0,
             'online': True,
             'static': {'countryCode': 'CA', 'deviceType': '401'},
             'timestamp': 1593872188258.0},
'softapId': '',
'softapPass': '',
'ssid': 'MYSSIDNAME',
'tclcount': 0,
'tftYn': 'N',
'timezoneCode': 'America/Toronto',
'timezoneCodeAlias': 'USA/Toronto',
'userNo': 'MYLGUSERNUMBER',
'utcOffset': -5,
'utcOffsetDisplay': '-05:00'}

@SkOODaT
Copy link

SkOODaT commented Jul 12, 2020

@ThatWileyGuy can you fork and push your modifications, ill take a crack at it with you :)

@ljtilley
Copy link

@ThatWileyGuy, @SkOODaT. I took a crack at this a couple weeks ago and was able to control my apiv2 a/c with the thinq2-python library, so however that person has it implemented works. The only part missing is they haven't implemented the control/control-sync API endpoint, so I added that in. I'm not sure of the difference between the two, they both seem to work to control stuff.

I also looked at the raw API requests coming from the app and it looks like there is a step to register the individual client-id that the v1 api does not require. I checked with the thinq2-api library and verified that this step does need to happen or else the control-sync/control endpoints won't work, so at minimum, we'd need to implement:

  1. unique client-id generation instead of hard-coding it into the headers and
  2. check that the client-id is registered before a session is initiated (and register it if it's not already done).

I started looking at the wideq codebase to implement v2 and it seems like APIv2 does things just differently enought at a basic level to make it challenging to implement v2 in a way that doesn't break v1 compatibility. Currently the way devices are implemented in wideq makes a few assumptions about how the api works that would have to be changed to work with v2, e.g.

@property
def supported_operations(self):
     """Get a list of the ACOp Operations the device supports.
    """
    mapping = self.model.value('Operation').options
    return [ACOp(o) for i, o in mapping.items()]

If the goal is to maintain compatibilty with the v1 api, then we might need to create an intermediate abstraction with different implementations for apiv1 and apiv2. Reiterating what @ThatWileyGuy said, it would be helpful to have the device info for v1 devices posted somewhere to make sure the new implementation will still work with older devices since I'm sure many v2 device owners (myself included) only have access to v2 devices.

@craigsheppard
Copy link

I currently have a wall-mounted LG heat pump head (ac unit) with built-in WiFi, running on the v2 api, and a ceiling cassette with the old USB adapter running the v1 api. Both are registered and available in LG's app.

With the current WideQ implementation I only see the ceiling cassette.

Let me know if there's something I can do help get the device info you need.

If the goal is to maintain compatibilty with the v1 api, then we might need to create an intermediate abstraction with different implementations for apiv1 and apiv2. Reiterating what @ThatWileyGuy said, it would be helpful to have the device info for v1 devices posted somewhere to make sure the new implementation will still work with older devices since I'm sure many v2 device owners (myself included) only have access to v2 devices.

@craigsheppard
Copy link

craigsheppard commented Jul 13, 2020

@SkOODaT

post a V1 response if you can, we need it to refer to so V1 doesnt break adding V2 (remember to remove sensitive info~)

Are you looking for the wideq.ACDevice().device info? See below:

{'data': {'alias': 'MainAC',
          'appModuleSize': 5427622,
          'appModuleUri': 'https://aic.lgthinq.com:46030/api/webContents/moduleDownload?type=appModule/GAM/•••&fileName=GAM_rev22679.zip&authKey=thinq',
          'appModuleVer': 2,
          'appRestartYn': 'Y',
          'curOffset': -3,
          'curOffsetDisplay': '-03:00',
          'deviceCode': 'AI04',
          'deviceId': '•••',
          'deviceState': 'E',
          'deviceType': 401,
          'dstOffset': -3,
          'dstOffsetDisplay': '-03:00',
          'fwVer': '2.6.4_RTOS_3K',
          'imageUrl': 'https://aic.lgthinq.com:46030/api/webContents/imageDownload?type=modelType&image=home_sac_img.png',
          'langPackModelUri': '',
          'langPackModelVer': '',
          'langPackProductTypeUri': 'https://aic.lgthinq.com:46030/api/webContents/moduleDownload?type=langPack/PP/401/PP_401_LANG_EN-CA_VER_40.4_NUTS.json&fileName=PP_401_LANG_EN-CA_VER_40.4_NUTS&authKey=thinq',
          'langPackProductTypeVer': 40.4,
          'macAddress': '•••',
          'modelJsonUrl': 'https://aic.lgthinq.com:46030/api/webContents/modelJSON?modelName=modelJSON_401&countryCode=KR&contentsId=•••&authKey=thinq',
          'modelJsonVer': 10.5,
          'modelNm': 'CST_570004_WW',
          'networkType': '02',
          'newRegYn': 'N',
          'regDt': 20200709230926,
          'regDtUtc': 20200710020926,
          'remoteControlType': 'REMO_CST_WIRELESS_BE',
          'sdsGuide': '{"deviceCode":"AI04"}',
          'smallImageUrl': 'https://aic.lgthinq.com:46030/api/webContents/imageDownload?type=modelType/Small&image=home_sac_img.png',
          'ssid': '•••',
          'ssidPass': '',
          'subModelNm': '',
          'timezoneCode': 'America/Halifax',
          'timezoneCodeAlias': 'USA/Halifax',
          'utcOffset': -4,
          'utcOffsetDisplay': '-04:00',
          'workId': ''}}```

@SkOODaT
Copy link

SkOODaT commented Jul 13, 2020

lol thank you @ljtilley i had it partially added but couldn't figure it fully out, took about 2 sec and i was able to power on my AC

info = thinq.mqtt.thinq_client.control_sync('ID#', 'Operation', 'basicCtrl', 'airState.operation', '{%airState.operation%}')
print(info)

True
seems theirs going to be alot of work figuring things out tho

edit:
this is on
thinq.mqtt.thinq_client.control_sync('XXXXXXXXXXX', 'Operation', 'basicCtrl', 'airState.operation', '1')
this is off
info = thinq.mqtt.thinq_client.control_sync('XXXXXXXXXXX', 'Operation', 'basicCtrl', 'airState.operation', '0')
this will set temp
thinq.mqtt.thinq_client.control_sync('XXXXXXXXXXX', 'Set', 'basicCtrl', 'airState.tempState.target', '18')
modes
thinq.mqtt.thinq_client.control_sync('XXXXXXXXXXX', 'Set', 'basicCtrl', 'airState.opMode', '0')) # - 0 COOL, 1 DRY, 2 FAN

ill continue to add to this as i figure functions out for my 'model_name': 'POT_056905_WW', AC
how do they correspond model to thier model json control scheme? it seems like ever function for every AC is in that json how do they reference what AC works with what commands lol i feel like something is missing

@javawizard
Copy link

Just seeing this - I've got an LG window air conditioner that requires API V2 that I'd love to get connected to HA and some spare time and coding chops to throw your way.

Where's the best place for me to get started? What's needed at this point?

@sampsyo
Copy link
Owner

sampsyo commented Jul 23, 2020

Great! The main thing we need is some serious hacking attention to bring together the heroic effort folks have already made to figure out the API and bring it in line with the whole library. Cloning the branch from this PR, trying it out, and fixing bugs would be a great way to start.

@javawizard
Copy link

javawizard commented Jul 23, 2020

@sampsyo - Can do. Is there any particular place the community has collected what they've worked out about the V2 protocol beyond the comments on this PR and the code comments on the branch?

@sampsyo
Copy link
Owner

sampsyo commented Jul 24, 2020

Rad! Alas, no—there is no real central place where this stuff is being collected. However, @tinkerborg does have another effort that I believe inspired @ollo69 to do this set of changes, which might be helpful: https://github.com/tinkerborg/thinq2-python

@javawizard
Copy link

Got it. I checked that out last night and got it up and running and watching events from my air conditioner - so progress! @tinkerborg - I notice you haven't done anything with thinq2-python since May - are you planning to do more or is that going by the wayside?

@tinkerborg
Copy link

Got it. I checked that out last night and got it up and running and watching events from my air conditioner - so progress! @tinkerborg - I notice you haven't done anything with thinq2-python since May - are you planning to do more or is that going by the wayside?

Still planning to work on it, but haven't been able to lately for various reasons. I hope to finish it off soon.

@town3r
Copy link

town3r commented Aug 3, 2020

Anything I can do to help w/ adding support for LG dehumidifiers?

@SkOODaT
Copy link

SkOODaT commented Sep 18, 2020

quiet lol, has anyone noticed this ....
https://github.com/pneumaticdeath/wideq/commits/api2_rebased
looks liek they have it working, i get a proper state file with all the data, allthough i couldnt get any functions working yet, thier errors ~
the one thing that works for me is the device information at the start lol but its a Very good start

def ls(client):
    """List the user's devices."""

    for device in client.devices:
        print('{0.id}: {0.name} ({0.type.name} {0.model_id})'.format(device))
        print(device.id)
        device = client.get_device(device.id)
        print(dir(device))
        print(getattr(device, 'data'))

{'appType': 'NUTS', 'modelCountryCode': 'WW', 'countryCode': 'CA', 'modelName': 'POT_056905_WW', 'deviceType': 401, 'deviceCode': 'AI01', 'alias': 'AirConditioner', 'deviceId': 'ea70337........
seems to ALL be there

@davewatson91
Copy link

Hi @sampsyo - any way I can help to bring this back to life - I have a V2 LG system in Australia - with a bit but not heaps of python experience - super keen to get my AC running through HA though.

@wishie
Copy link

wishie commented Nov 1, 2020

I am about to pull the trigger on purchasing an LG ducted system for my house.. its an older model (but new) so might use APIv1? But I assume my newly created LG account might be APIv2 only? Is that the current issue?

@Codex-
Copy link

Codex- commented Jan 2, 2021

quiet lol, has anyone noticed this ....
https://github.com/pneumaticdeath/wideq/commits/api2_rebased
looks liek they have it working, i get a proper state file with all the data, allthough i couldnt get any functions working yet, thier errors ~

I can confirm using their fork that I can see the machine I couldn't see with the current stable of this repo.

@pneumaticdeath would you be willing to make a PR here with your changes to get v2 working? Would be a good start, happy to help and review too.

EDIT: Looks like @no2chem has this working too over in their fork: https://github.com/no2chem/wideq/tree/thinq2

Would be great to see a PR to get the ball rolling again

@pneumaticdeath
Copy link

pneumaticdeath commented Jan 2, 2021 via email

@tinkerborg
Copy link

tinkerborg commented Jan 2, 2021

Hi, for folks that have been talking about API v2 support, I did get most of the v2 API implemented, including auth, retrieving device data, and state updates via MQTT (along with generic MQTT connectivity). The events of 2020 have left me particularly drained so I haven't found the motivation to finish it yet, but the last piece really needed is device control. The work in progress can be found here: https://github.com/tinkerborg/thinq2-python - whether you want to use it as a reference or just implement the device control part and send a PR.

@SkOODaT
Copy link

SkOODaT commented Jan 2, 2021

its winter here so thats why i havent had motivation to continue, the AC is away-ish lol that being said its still plugged in and connected so id be willing to test anything you guys push lol, be nice if we could get it all sorted by this summer 😜

with some of the stuff around i was able to control and do a few various things with mine a few months ago i think i posted it all above ~

also on side note as far as i can tell nothing has changed with the api, im still running a node version and nothing has been changed with it in months ~

@pneumaticdeath
Copy link

pneumaticdeath commented Jan 4, 2021 via email

@marleyjaffe
Copy link

As a new LG product owner, how can I tell if my appliance is api v2?

@krystof-k
Copy link
Contributor

In my case, the FW version in the LG ThinQ app is very different:

API v1:
IMG_0351

API v2:
IMG_0350

@Btje1977
Copy link

Btje1977 commented Mar 8, 2021

Did you see this version they are working on:

ollo69/ha-smartthinq-sensors#124 going to branche https://github.com/ollo69/ha-smartthinq-sensors/tree/AC-Implementation

Maybe a good idea to join effort?

@fuselinks
Copy link

i have problem on hoobs
"12.08.2021, 09:55:10Lg Airco BridgeERROR[Lg Airco Bridge 2F90@LG Sypialnia@LG Sypialnia@Target Heater-Cooler State] characteristic value 0 is not contained in valid values array
12.08.2021, 09:55:10Lg Airco BridgeERROR[Lg Airco Bridge 2F90@LG Office@LG Office@Target Heater-Cooler State] characteristic value 0 is not contained in valid values array
12.08.2021, 09:55:10Lg Airco BridgeERROR[Lg Airco Bridge 2F90@LG Salon@LG Salon@Target Heater-Cooler State] characteristic was supplied illegal value: number 3 exceeded maximum of 2"

@KlavsKlavsen
Copy link

This seems abandoned.. have people found other solutions to operate their thinq api2 devices, or?

@pniewiadowski
Copy link

This seems abandoned.. have people found other solutions to operate their thinq api2 devices, or?

I ma just using this: https://github.com/ollo69/ha-smartthinq-sensors

@lvlie
Copy link

lvlie commented Dec 21, 2023

Been using https://github.com/ollo69/ha-smartthinq-sensors for a year or 2 already, without any issues.
Good luck 👍

Edit: sorry for double post, was just beaten to it by mere seconds 😉

@digginsa
Copy link

digginsa commented Dec 21, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet