LG Smart ThinQ

One additional note: Using thinq2-python is just a workaround for me. I know the wideq-maintainers are working hard to get V2 implemented. As soon they have a stable implementation, I will switch back to wideq as it will then support V1 and V2…

nope i really didnt see your pm…i do now :slight_smile: thnx for your answer,i will try it again when i get home from work.I just need a tip how to send the devices state to my mqtt broker running on my openhabian pi.
Thank u

After you’ve got thinq2-python running, you can download my modified version (based on the example.py):

cd /etc/openhab2/scripts/thinq2-python
wget https://raw.githubusercontent.com/Flip76/thinq2_mqtt/main/thinq_mqtt.py

Edit the file and adjust the mqtt_-variables to your environment.

You can run it with:

poetry run python3 thinq_mqtt.py

Now walk to your LG device and try it :slight_smile:

I am using mqtt explorer for windows to connect to the broker and check the results…

Interesting. I’ll keep an eye on this thread and try things again tomorrow. What I have found out is I’m
NZ and en-NZ which is a start, even if it ultimately ends up on the Korean Server

I ended up on the Korean server too - but it seems to work

Last week I was playing with the code from “wideq” repository and its forks. Here are my findings:

  1. Original “wideq” repo supports only v1 of the protocol.

  2. Most of the recently created accounts is using v2 of the protocol.

  3. There is already plugin for Home Assistant which works with v2 only - https://github.com/ollo69/ha-smartthinq-sensors

  4. There is fork of the original “wideq” repository which supports v2 - https://github.com/pneumaticdeath/wideq.git - branch api2_merged.

  5. Comments in the codebase from #3 shows that ls and mon commands are not longer needed for v2, as the initial request returns all the data - it is sufficient to call example.py,

  6. Important data in the returned JSON is located in node refState:

     "refState": {
             "displayLock": "UNLOCK",
             "freezerTemp": 7.0,
             "sabbathMode": "OFF",
             "tempUnit": "CELSIUS",
             "ecoFriendly": "OFF",
             "activeSaving": "OFF",
             "expressFridge": "OFF",
             "smartSavingRun": "STOP",
             "atLeastOneDoorOpen": "CLOSE",
             "fridgeTemp": 2.0,
             "expressMode": "OFF",
             "dualFridgeMode": "IGNORE",
             "freshAirFilter": "IGNORE",
             "monStatus": "NORMAL",
             "smartSavingMode": "OFF",
             "convertibleTemp": 0.0,
             "waterFilter": "0_MONTH"
         },
    
  7. Don’t be confused with odd values for freezerTemp and fridgeTemp - based on the link from to the json schema returned in the response (in the field modelJsonUri), you need to convert them (mapping for Celcius)

    a. freezerTemp:

            "valueMapping": {
               "1":   {"index" : 1,    "label" : "-15", "_comment" : ""},
               "2":   {"index" : 2,    "label" : "-16", "_comment" : ""},
               "3":   {"index" : 3,    "label" : "-17", "_comment" : ""},
               "4":   {"index" : 4,    "label" : "-18", "_comment" : ""},
               "5":   {"index" : 5,    "label" : "-19", "_comment" : ""},
               "6":   {"index" : 6,    "label" : "-20", "_comment" : ""},
               "7":   {"index" : 7,    "label" : "-21", "_comment" : ""},
               "8":   {"index" : 8,    "label" : "-22", "_comment" : ""},
               "9":   {"index" : 9,    "label" : "-23", "_comment" : ""},
               "255" : {"index" : 255,   "label" : "IGNORE", "_comment" : ""}
         }
    

    b. fridgeTemp

            "valueMapping": {
               "1": {"index" : 1,   "label" : "7", "_comment" : ""},
               "2": {"index" : 2,   "label" : "6", "_comment" : ""},
               "3": {"index" : 3,   "label" : "5", "_comment" : ""},
               "4": {"index" : 4,   "label" : "4", "_comment" : ""},
               "5": {"index" : 5,   "label" : "3", "_comment" : ""},
               "6": {"index" : 6,   "label" : "2", "_comment" : ""},
               "7": {"index" : 7,   "label" : "1", "_comment" : ""},
               "255" : {"index" : 255,   "label" : "IGNORE", "_comment" : ""}
    
  8. It would be nice to find a way to register for push messages from LG if there is any change to the device; or extract more data, like energy consumption.

  9. Hope that with those finding someone could create binding (focusing only on v2 protocol)

1 Like

I’ve just tried your instructions which all seemed to work until this step.

In my case it was

COUNTRY_CODE=NZ LANGUAGE_CODE=en-NZ poetry run python3 example.py

that seemed to break it, but after trying again I’ve managed to get it to work and its now giving status updates using thinq_mqtt,py

Interestingly its reported as a washer drier when its actually a plain washer. Also the app seems to send everything out once the go button is pressed whereas the control knob on the machine sends updates whenever its turned.

Has anyone worked out how to send commands?

I’d like to send something like start command together with delay finish for xx hours, that way I can make a rule that has a predictable finish time. It seems my machine does a calculation after sending something like start and delay finish for 3 hours once the command is sent, and then it goes to sleep until it needs to start.
Quite a difference from my easily fooled 15 YO Bosch

Also the mqtt messages are only sent when they change, for example remainTimeHour is only sent when it changed from 1 to 0 during the current cycle

@kevin I observed a similar behaviour… The updates coming from the LG API are only the changed values (together with some default values). remainTimeHour is sent together with remainTimeMinute immediately after pressing the start-button on the washer/dryer. After that, only remainTimeMinute will be updated every 1 minute until you reach 0:59 - then 0 will be received as remainTimeHour.

The point is that you only get all values if your broker is online before you start the washer/dryer. But I will have a play over the weekend to see if I can find a workaround.

I didn’t try to send commands to the machine yet (as to my knowledge it would always require to enable the remote-start-function manually at the machine - imho this makes the whole function pointless) but I will also try it over the weekend.

Regarding the reported device type… Here I can’t do anything as this is coming directly from LG and in order to “correct” that, you would need create/access a LG device database (but this is out of the scope of this project)

Perhaps there is a way to request a full update

allDeviceInfoUpdate : False

Makes me wonder

As the values aren’t retained on the broker I suspect the easiest way is to just persist the values, which is what I’ll do if it becomes a problem. Theres also an interplay between reserveTimeHour, reserveTimeMinute and remainingTimeHour, remainingTimeMinute which comes in when the delayed finish is used. I think I know whats happening but I need to use it a few more times before I’m sure.

Regarding sending commands I have a free hour of electricity every day from my power company so I schedule the washer to finish just before it starts so I can start the drier, I can change the hour with an app, so setting delayed finish changing automatically with OH will be a lot easier. I’ll just load it and select delayed start assuming the value doesn’t stick between cycles

This was more a curiousity, I don’t actually use it.

One final question, where do you reckon is the best place to run the script from so it starts with the OH box - rc.local?

As the values aren’t retained on the broker I suspect the easiest way is to just persist the values, which is what I’ll do if it becomes a problem. Theres also an interplay between reserveTimeHour, reserveTimeMinute and remainingTimeHour, remainingTimeMinute which comes in when the delayed finish is used. I think I know whats happening but I need to use it a few more times before I’m sure.

I want to try retaining the values on MQTT-level… I saw with PAHO-MQTT I can add qos and retain…

Regarding sending commands I have a free hour of electricity every day from my power company so I schedule the washer to finish just before it starts so I can start the drier, I can change the hour with an app, so setting delayed finish changing automatically with OH will be a lot easier. I’ll just load it and select delayed start assuming the value doesn’t stick between cycles

Ok, got it… I will check to send commands (also trying to play around with allDeviceInfoUpdate)…

One final question, where do you reckon is the best place to run the script from so it starts with the OH box - rc.local?

I just created a small systemd service (please adjust your path accordingly):

vi /lib/systemd/system/thinq-mqtt.service

[Unit]
Description=thinq-mqtt
After=mosquitto.service

[Service]
ExecStart=/bin/bash -c "PATH=/home/openhabian/.poetry/bin:$PATH exec poetry run python3 thinq_mqtt.py"
Restart=always
User=openhabian
Group=openhabian
WorkingDirectory=/etc/openhab2/scripts/thinq2-python

[Install]
WantedBy=multi-user.target

Then run this commands:

sudo systemctl daemon-reload
sudo systemctl start thinq-mqtt.service
sudo systemctl status thinq-mqtt.service

If everything is ok, just enable the service (to start on reboot):

sudo systemctl enable thinq-mqtt.service

Worked a charm once I changed the user to root. After much playing around I couldn’t get it to work from a command prompt or as a service with user openhab.
I’m running on Debian and its not the first time this has happened :slight_smile:
Thanks very much for your help, whilst I’ve been using Linux for a few years now its not my natural environment

Sorry, I forgot the sudo for the vi-command - it should have been:

sudo vi /lib/systemd/system/thinq-mqtt.service

But glad you managed to get it working

Meanwhile I researched the possibility to send commands… Unfortunately it seems that currently this is not supported by API V2. I requested access to LG developers area in order to get the API documentation but the request has been denied.

So the only chance I see is that the guys from wideq or thinq2-python will come up with a solution…

I modified the script to support retaining messages - you can give it a try:

cd /etc/openhab2/scripts/thinq2-python
wget https://raw.githubusercontent.com/Flip76/thinq2_mqtt/main/thinq_mqtt.py

Pity about the APi, it seems when you turn on the machine, load it and then press the remote start button it goes to sleep after around 14 minutes and it can be woken by the app. Once awake the cycle and other stuff needs setting and then it will start, so it seems it would do what I need if only there was a way of copying what the app sends…

Regarding retained messages I copied the script over, rebooted the box, changed a few things from the washer front panel, then disconnected MQTT Explorer. I then reconnected it and nothing to do with the washer appeared until I touched the front panel again suggesting the messages are not retained?

Are you using Mosquitto?

My output looks like:

poetry install gives me an error :

openhabian@openhab:/etc/openhab2/scripts/thinq2-python$ poetry install
Installing dependencies from lock file

Package operations: 35 installs, 0 updates, 0 removals

  • Installing cffi (1.14.0): Failed

  EnvCommandError

  Command ['/home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/bin/pip', 'install', '--no-deps', 'file:///home/openhabian/.cache/pypoetry/artifacts/c5/36/a2/454cd9909af7ef4a484abd959b4abc393e7ff39ec0a73eeac1763da0ea/cffi-1.14.0.tar.gz'] errored with the following return code 1, and output:
  Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
  Processing /home/openhabian/.cache/pypoetry/artifacts/c5/36/a2/454cd9909af7ef4a484abd959b4abc393e7ff39ec0a73eeac1763da0ea/cffi-1.14.0.tar.gz
  Building wheels for collected packages: cffi
    Building wheel for cffi (setup.py): started
    Building wheel for cffi (setup.py): finished with status 'error'
    ERROR: Command errored out with exit status 1:
     command: /home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-req-build-ydg37rdr/setup.py'"'"'; __file__='"'"'/tmp/pip-req-build-ydg37rdr/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-8970z7_t
         cwd: /tmp/pip-req-build-ydg37rdr/
    Complete output (56 lines):
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    running bdist_wheel
    running build
    running build_py
    creating build
    creating build/lib.linux-armv7l-3.7
    creating build/lib.linux-armv7l-3.7/cffi
    copying cffi/__init__.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/cffi_opcode.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/verifier.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/vengine_cpy.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/commontypes.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/pkgconfig.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/setuptools_ext.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/recompiler.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/lock.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/cparser.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/backend_ctypes.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/vengine_gen.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/model.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/ffiplatform.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/api.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/error.py -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/_cffi_include.h -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/parse_c_type.h -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/_embedding.h -> build/lib.linux-armv7l-3.7/cffi
    copying cffi/_cffi_errors.h -> build/lib.linux-armv7l-3.7/cffi
    running build_ext
    building '_cffi_backend' extension
    creating build/temp.linux-armv7l-3.7
    creating build/temp.linux-armv7l-3.7/c
    arm-linux-gnueabihf-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DUSE__THREAD -DHAVE_SYNC_SYNCHRONIZE -I/usr/include/ffi -I/usr/include/libffi -I/home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/include -I/usr/include/python3.7m -c c/_cffi_backend.c -o build/temp.linux-armv7l-3.7/c/_cffi_backend.o
    c/_cffi_backend.c:15:10: fatal error: ffi.h: No such file or directory
     #include <ffi.h>
              ^~~~~~~
    compilation terminated.
    error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1
    ----------------------------------------
    ERROR: Failed building wheel for cffi
    Running setup.py clean for cffi
  Failed to build cffi
  Installing collected packages: cffi
      Running setup.py install for cffi: started
      Running setup.py install for cffi: finished with status 'error'
      ERROR: Command errored out with exit status 1:
       command: /home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-req-build-ydg37rdr/setup.py'"'"'; __file__='"'"'/tmp/pip-req-build-ydg37rdr/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-ett98yo2/install-record.txt --single-version-externally-managed --compile --install-headers /home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/include/site/python3.7/cffi
           cwd: /tmp/pip-req-build-ydg37rdr/
      Complete output (56 lines):
      Package libffi was not found in the pkg-config search path.
      Perhaps you should add the directory containing `libffi.pc'
      to the PKG_CONFIG_PATH environment variable
      No package 'libffi' found
      Package libffi was not found in the pkg-config search path.
      Perhaps you should add the directory containing `libffi.pc'
      to the PKG_CONFIG_PATH environment variable
      No package 'libffi' found
      Package libffi was not found in the pkg-config search path.
      Perhaps you should add the directory containing `libffi.pc'
      to the PKG_CONFIG_PATH environment variable
      No package 'libffi' found
      Package libffi was not found in the pkg-config search path.
      Perhaps you should add the directory containing `libffi.pc'
      to the PKG_CONFIG_PATH environment variable
      No package 'libffi' found
      Package libffi was not found in the pkg-config search path.
      Perhaps you should add the directory containing `libffi.pc'
      to the PKG_CONFIG_PATH environment variable
      No package 'libffi' found
      running install
      running build
      running build_py
      creating build
      creating build/lib.linux-armv7l-3.7
      creating build/lib.linux-armv7l-3.7/cffi
      copying cffi/__init__.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/cffi_opcode.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/verifier.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/vengine_cpy.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/commontypes.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/pkgconfig.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/setuptools_ext.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/recompiler.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/lock.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/cparser.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/backend_ctypes.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/vengine_gen.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/model.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/ffiplatform.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/api.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/error.py -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/_cffi_include.h -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/parse_c_type.h -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/_embedding.h -> build/lib.linux-armv7l-3.7/cffi
      copying cffi/_cffi_errors.h -> build/lib.linux-armv7l-3.7/cffi
      running build_ext
      building '_cffi_backend' extension
      creating build/temp.linux-armv7l-3.7
      creating build/temp.linux-armv7l-3.7/c
      arm-linux-gnueabihf-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DUSE__THREAD -DHAVE_SYNC_SYNCHRONIZE -I/usr/include/ffi -I/usr/include/libffi -I/home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/include -I/usr/include/python3.7m -c c/_cffi_backend.c -o build/temp.linux-armv7l-3.7/c/_cffi_backend.o
      c/_cffi_backend.c:15:10: fatal error: ffi.h: No such file or directory
       #include <ffi.h>
                ^~~~~~~
      compilation terminated.
      error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1
      ----------------------------------------
  ERROR: Command errored out with exit status 1: /home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-req-build-ydg37rdr/setup.py'"'"'; __file__='"'"'/tmp/pip-req-build-ydg37rdr/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-ett98yo2/install-record.txt --single-version-externally-managed --compile --install-headers /home/openhabian/.cache/pypoetry/virtualenvs/thinq2-O76D47mt-py3.7/include/site/python3.7/cffi Check the logs for full command output.


  at ~/.poetry/lib/poetry/utils/env.py:948 in _run
       944│                 output = subprocess.check_output(
       945│                     cmd, stderr=subprocess.STDOUT, **kwargs
       946│                 )
       947│         except CalledProcessError as e:
    →  948│             raise EnvCommandError(e, input=input_)
       949│
       950│         return decode(output)
       951│
       952│     def execute(self, bin, *args, **kwargs):

Did you follow those steps?

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 -

vi $HOME/.poetry/bin/poetry

change this line:

#!/usr/bin/env python
to
#!/usr/bin/env python3

source $HOME/.poetry/env

yeap,exactly

yes, several instances of it on different ports. Retained shows up elsewhere as expected