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

Any one wrapped this as a Home Assistant Add-On? #174

Open
leaskovski opened this issue Sep 8, 2024 · 2 comments
Open

Any one wrapped this as a Home Assistant Add-On? #174

leaskovski opened this issue Sep 8, 2024 · 2 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request help wanted Extra attention is needed

Comments

@leaskovski
Copy link

Has any wrapped this up as a docker file that can be used with Home Assistant? I might have a go at trying to do this, but don't have much experience, however if someone has already done it, then great!!!

@TheRoarman
Copy link

or an add-on via HACS for some that are running HA OS

@AlmightyCZ
Copy link

Workaround: Using withings-sync with AppDaemon in Home Assistant

I put together this workaround to integrate withings-sync with Home Assistant using AppDaemon. It's the result of trial and error, so it might not be perfect. Here's how to set it up:


Steps:

  1. Install AppDaemon Add-On:

    • Install the AppDaemon add-on from the Home Assistant Add-on Store.
    • Enable "Start on boot" and start the add-on.
  2. Add Required Python Packages:

    • In the AppDaemon configuration, add these to the python_packages section:
      • withings-sync
      • pexpect
    • Save and restart AppDaemon.
  3. Create the Script:

    • In your AppDaemon apps folder (e.g., data/addon_configs/a0d7b954_appdaemon/apps/), create a file withings_sync_runner.py with this code:
import appdaemon.plugins.hass.hassapi as hass
import subprocess
import time
import pexpect
import os

def read_and_clear_file(filepath):
    """Reads and clears the content of the file, returns the content."""
    with open(filepath, 'r', encoding='utf-8') as file:
        content = file.read().strip()
    if content:
        # Clear the file content after reading
        with open(filepath, 'w', encoding='utf-8') as file:
            file.write('')
    return content


class WithingsSyncRunner(hass.Hass):

    def initialize(self):
        self.listen_event(self.run_sync_event, "WITHINGS_SYNC_START")
        self.listen_event(self.run_test, "WITHINGS_SYNC_TEST")
    
    def ha_notify(self, msg):
        self.call_service("notify/pavel_notification_group", title="Withings Sync", message=msg)

    def run_test(self, event_name, data, kwargs):
        self.ha_notify("test")

    def log_error(self, message):
        """Logs error messages using `ascii_encode=False`."""
        self.log(message, ascii_encode=False)
        self.ha_notify(message)

    def run_sync_event(self, event_name, data, kwargs):
        os.environ["WITHINGS_USER"] = "/config/apps/withings_user.json"
        os.environ["GARMIN_SESSION"] = "/config/apps/garmin_session"
        self.log("Starting sync...")
        child = pexpect.spawn('withings-sync --garmin-username=USERNAME --garmin-password=PASSWORD')

        prompts = ['Enter MFA code', 'Token :', 'MFA code:']

        try:
            while True:
                index = child.expect(prompts + [pexpect.EOF, '\n'], timeout=-1)
                if index < len(prompts):  # Prompt detected
                    token_msg = f"Prompt detected: {prompts[index]}"
                    self.ha_notify(token_msg)
                    self.log(token_msg, ascii_encode=False)
                    token = None
                    waiting_time = 0
                    max_waiting_time = 300  # 5 minutes
                    self.log("Waiting for code...", ascii_encode=False)
                    while not token and waiting_time < max_waiting_time:
                        token = read_and_clear_file('/config/apps/input.txt')
                        time.sleep(5)  # Waiting for the file to be updated
                        waiting_time += 5
                    if not token:
                        self.log_error("Time to enter the code has expired.")
                        break
                    self.log(f"Code received: {token}", ascii_encode=False)
                    child.sendline(token)
                elif index == len(prompts):  # EOF - End of file (process finished)
                    self.log("Process finished", ascii_encode=False)
                    break
                else:
                    # Output the response if no specific prompt is detected
                    print(child.before.decode('utf-8', errors='ignore').strip())
        except pexpect.exceptions.TIMEOUT:
            self.log_error("Timeout occurred.")
            self.log(f"Output before timeout: {child.before.decode('utf-8', errors='ignore').strip()}", ascii_encode=False)
        except pexpect.exceptions.EOF:
            self.log_error("Process ended prematurely.")
            self.log(f"Output before EOF: {child.before.decode('utf-8', errors='ignore').strip()}", ascii_encode=False)
        except Exception as e:
            self.log_error(f"Unexpected error: {e}")
  • Replace USERNAME and PASSWORD with your Garmin credentials.
  • Replace notify/pavel_notification_group with your device/group for MFA and error notifications.
  1. Trigger Sync:
    • Use a Home Assistant automation or script to fire the WITHINGS_SYNC_START event.

      Example for automation actions:

         actions:
           - event: WITHINGS_SYNC_START
             event_data: {}

Notes:

  • MFA Handling: When prompted, enter the MFA code into input.txt (you may need to create the file first). The script will pick it up automatically.
  • Security: Credentials are stored in plain text, so use with caution.

(Disclaimer: I've never worked with Python before, so this is just a workaround I managed to put together. Any suggestions or improvements are more than welcome!)

@longstone longstone added documentation Improvements or additions to documentation enhancement New feature or request help wanted Extra attention is needed labels Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants