Withings-Sync Python/Powershell Script w/ Discord Webhook Notifications

I recently deployed https://github.com/jaroslawhartman/withings-sync to sync my Withings scale to my Garmin account. Here’s a quick Powershell script I whipped up that runs via Scheduled Tasks on Windows and uses a Discord Webhook to notify you of its progress:

# function adapted from https://stackoverflow.com/posts/42995301/revisions
Function Execute-Command ($commandTitle, $commandPath, $commandArguments)
{
Try {
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $commandPath
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $commandArguments
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
[pscustomobject]@{
commandTitle = $commandTitle
stdout = $p.StandardOutput.ReadToEnd()
}
$p.WaitForExit()
}
Catch {
exit
}
}
# call this with garmin username & password to sync from withings
function withings-sync( $username, $password )
{
# setup vars
$hoursToPause = 2
$fromDate = Get-Date
$loop = $true
$countOfTries = 0
$maxTries = 10
$user = $username
$pwd = $password
$wsPath = "C:\python38\scripts\withings-sync.exe"
# discord setup
$discordBot = "Withings -> Garmin Sync"
$hookUrl = "https://discord.com/api/webhooks/xxxx"
$content = "{0:HH:mm:ss}: Garmin upload beginning for $user." -f ( (Get-Date) )
$section = New-DiscordSection -Title "Info" -Description $content -Color LightGrey
# send discord update on start
Write-Host $content
Send-DiscordMessage -webHookUrl $hookUrl -Sections $section -AvatarName $discordBot
do
{
# only retry $maxTries times
if($countOfTries -lt $maxTries)
{
# create args, then try withings-sync upload and capture output
$args = ("–garmin-username ${user} –garmin-password ${pwd} –fromdate {0:yyyy-MM-dd}" -f $fromDate).ToString()
$process = Execute-Command -commandTitle "Withings->Garmin Sync" -commandPath $wsPath -commandArguments $args
$outputText = $process.stdout
Write-Host $outputText
# if upload worked, break loops
if( $outputText.Contains("Fit file uploaded to Garmin Connect") )
{
$content = "{0:HH:mm:ss}: Garmin upload successful for $user." -f ( (Get-Date) )
$section = New-DiscordSection -Title "Info" -Description $content -Color Green
$loop = $false
}
# if no measurements, wait and try again later
elseif( $outputText.Contains("No measurements to upload for date or period specified") )
{
$content = "{0:HH:mm:ss}: No Withings measurements found for $user; sleeping $hoursToPause hour(s) and trying again." -f ( (Get-Date) )
$section = New-DiscordSection -Title "Alert" -Description $content -Color Yellow
}
# if withings refresh failed
elseif( $outputText.Contains("withings – ERROR") )
{
$content = "{0:HH:mm:ss}: Withings refresh failed for $user; sleeping $hoursToPause hour(s) and trying again." -f ( (Get-Date) )
$section = New-DiscordSection -Title "Alert" -Description $content -Color Red
}
# if garmin upload failed
else
{
$content = "{0:HH:mm:ss}: Garmin upload failed for $user; sleeping $hoursToPause hour(s) and trying again." -f ( (Get-Date) )
$section = New-DiscordSection -Title "Alert" -Description $content -Color Red
}
# send discord update
Write-Host $content
Send-DiscordMessage -webHookUrl $hookUrl -Sections $section -AvatarName $discordBot
# pause for $countOfTries hour(s) and try again
$countOfTries = $countOfTries + 1
if($loop) { Start-Sleep ( $hoursToPause * 60 * 60 ) }
}
# after #maxTries failures, send discord update and exit the loop
else
{
$content = "{0:HH:mm:ss}: Garmin upload failed $maxTries times, aborting." -f ( (Get-Date) )
$section = New-DiscordSection -Title "Alert" -Description $content -Color Red
Write-Host $content
Send-DiscordMessage -webHookUrl $hookUrl -Sections $section -AvatarName $discordBot
$loop = $false
}
}
while ($loop -eq $true)
}

Install the PSDiscord powershell module. Set $hookUrl with your Discord Webhook URL. Setup your path to the Python withings-sync executable in the $wsPath variable, then call the withings-sync function from Powershell after initializing your Withings token with withings-sync manually, as per the github instructions (pass your Garmin credentials as the $username and $password parameters). The script will auto-retry up to $maxTries times every $hoursToPause.

Edited 2021-09-21: removed some code from the Execute-Command function that could cause a deadlock when Garmin spits out its 403 error and changed the order of the if/else statements slightly. Cheers!