Giter Club home page Giter Club logo

zwifit's Introduction

Zwifit

Welcome to the cryptically named Zwifit! This NodeJS app joins Zwift with treadmills running iFit® with Wi-Fi/Bluetooth.

Disclaimer: I'm not associated with either company. Their trademarks and content are their own. Heck, they might force me to take this down! But let's enjoy the run before they do.

How This Works

This software connects to your iFit® treadmill over Wi-Fi/Bluetooth to observe its speed and incline. It then broadcasts that information over Bluetooth in a standard protocol that apps like Zwift are able to understand.

What Treadmills Are Compatible?

At the moment it seems hit or miss on which iFit treadmills with Wi-Fi/Bluetooth work, but we are building a spreadsheet over at the following URL. Look through that. You may also be interested in the TreadSync app, which has a similar goal to this project, but runs in a slightly different way (on iOS devices).

http://bit.ly/TS-compat

Minimum Requirements

  1. A Wi-Fi/Bluetooth connected iFit® treadmill
  2. Zwift running on your favorite device
  3. A Raspberry Pi ZeroW or 3B running this software (this software works on versions of Mac OS X before Mojave, but our Bluetooth dependency is presently borked on Mojave -- Windows requires an external Bluetooth LE dongle be properly configured).
  4. For Wi-Fi connected treadmills: Know the IP address of your treadmill. (I recommend reserving this IP in your router so it doesn't change.)
  5. You need to be minimally comfortable with a command line / terminal. Or have a nerdy friend!

Raspberry Pi Zero W: https://www.amazon.com/CanaKit-Raspberry-Wireless-Complete-Starter/dp/B072N3X39J/ref=sr_1_4?ie=UTF8&qid=1546535245&sr=8-4&keywords=raspberry+pi+zero+w

Note: the above is NOT an affiliate link, I don't get anything from you clicking it. There are loads of other options and configurations for purchasing a Pi. If you're not in the US, you should be able to find a configuration that has a good power supply, a Zero W, and a MicroSD card. Or you could purchase the parts separately!

Software Requirements

Raspbian (Raspberry Pi)

This software works great on a Raspberry Pi 3b+ or a Raspberry Pi Zero W. Follow all of these steps on your Pi itself, not on your laptop or desktop! The easiest way to do this is to plug a monitor, keyboard and mouse in to your Pi. Or, if you've set up SSH, you can ssh in to your Pi to follow these steps (hint: this option is in the configuration UI).

  1. sudo apt-get update
  2. Install the dependencies we need: sudo apt-get install git bluetooth bluez libbluetooth-dev libudev-dev
  3. Install NodeJS 13.x
    1. For Raspberry Pi 3b+ run curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash - and sudo apt install -y nodejs
    2. For Raspberry Pi Zero W use the unofficial builds, because armv61 is not part of the official builds any more. Download the binaries, run
      • mkdir /opt
      • tar -C /opt -xzvf node-v13.8.0-linux-armv61.tar.gz
      • echo "export PATH=\$PATH:/opt/node-v13.8.0-linux-armv6l/bin" >> ~/.bashrc
      • exit and re-open terminal to activate changes
  4. Turn off the system Bluetooth daemon so we can control it: sudo systemctl disable bluetooth (to reverse this, change disable to enable)
  5. Turn the Bluetooth chip back on: sudo hciconfig hci0 up
  6. Give NodeJS access to Bluetooth without sudo: sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)

Windows

NOT WELL TESTED! Before you can run this code, you'll need to install a couple different things:

  1. NodeJS, specifically version 8: https://nodejs.org/dist/latest-v8.x/node-v8.14.0-x64.msi (The library we use to communicate over Bluetooth doesn't work with the latest versions of NodeJS yet.)
  2. Git https://git-scm.com/downloads
  3. To install node-gyp, after installing NodeJS, open a command prompt with "Run as administrator", and run the following: npm install --global --production windows-build-tools
  4. You'll need a compatible bluetooth adapter as well; follow the steps here: https://github.com/noble/node-bluetooth-hci-socket#windows

Mac OS X

DOES NOT WORK ON MOJAVE! Before you can run this code, you'll need to install a couple different things:

  1. NodeJS, specifically version 8: https://nodejs.org/dist/latest-v8.x/node-v8.14.0.pkg (The library we use to communicate over Bluetooth doesn't work with the latest versions of NodeJS yet.)
  2. Git: https://git-scm.com/downloads
  3. Xcode: https://developer.apple.com/xcode/

Getting Started

With the software requirements out of the way, you can run the following commands to get this program, set it up, and run it:

git clone https://github.com/dawsontoth/zwifit.git
cd zwifit
npm install
npm start

The last command will guide you through connecting to your treadmill. It will save your answers, and won't ask you in the future. Your answers are saved in the settings.conf file. To change them, simply edit settings.conf (or delete it and run npm start again).

Automatic Startup

Using PM2

Do you want this script to run in the background, even when you restart your computer? There are many ways to accomplish this. Personally, I use a program called PM2.

NOTE: To install this program globally, you can prefix sudo before the npm install line below, but it would be far wiser to tweak your installation of NPM so that sudo isn't required! Follow the steps in the following article, and you'll be doing your system a favor! https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally You only need to do this once.

Run the following to set everything up:

npm install -g pm2
pm2 startup
pm2 start app.js
pm2 save

You can undo this easily:

pm2 unstartup

Or restart, or view logs:

pm2 restart all
pm2 logs

Or update the code and restart:

git pull
pm2 restart all

Using cron with automatic shutdown

If you use a Raspberry Pi it is crucial to shutdown using

sudo poweroff

to avoid damaging the SD card (google for it to find more information). To perform this action after every workout in a convenient way there is the run-script raspberrypi.sh which can be used.

Details: If the environment variable SHUTDOWN_ONDISCONNECT=1 is set for the Zwifit process then Zwifit stops after loosing the Wifi/Bluetooth connection what is usually caused by switching off the treadmill. This situation is detected by the run-script raspberrypi.sh to shutdown your Raspberry Pi properly.

Since the shutdown procedure requires sudo it is advisable to start the shell script using the root cron. The run-script switches to the user pi for running Zwifit, so the root user is only used for shutdown.

To run Zwifit on startup edit the crontab by using

sudo crontab -e

and add this line at the end of the file:

@reboot nohup /home/pi/zwifit/raspberrypi.sh

(where you have to replace the path /home/pi/zwifit by the installation path of Zwifit at your system)

Once applied steps for using the system are:

  1. Plug in your Raspberry Pi.
  2. Wait until your treadmill enlights the connection led (or the control page http://raspberrypi.local:1337 is available and the ifit symbol is green) which takes 70 seconds using a Raspberry Pi ZeroW.
  3. Do your workouts with Zwift and connect or disconnect to the simulated treadmill as often you need to.
  4. Once you retire simple switch of your treadmill.
  5. About 10 seconds later it is save to plugin off your Raspberry Pi.

Calibration

Zwifit will report your treadmill's exact speed, as measured by the machine itself. You can use the calibration feature within Zwift to adjust this, just like you would with a footpod. Alternatively, load up the Zwifit Web UI and head to the Settings page.

Control and Monitoring

The app runs a local web server that displays information from your treadmill, allows changing settings, and allows manual control of speed and incline. This can be used to change the speed and incline of your treadmill, too. To access this web site, you'll need to know the IP of your Pi, or the hostname, depending on your wireless router. For me, I can access it at http://raspberrypi.local:1337/ You may need to do the full IP, such as http://192.168.0.50:1337/ -- or if you're running this on a laptop, at http://localhost:1337/

If you have a monitor or touch screen connected to your Pi, you can run it in Kiosk mode. It can launch the Zwifit UI automatically. Follow the steps in this article to get started: https://pimylifeup.com/raspberry-pi-kiosk/

Set the incline according to your current Zwift session

Zwift does not send the current gain of your running session to the treadmill. However, you can use the software zwifit-incline-tracker to achieve this regardless. These automatic updates are only processed if the treadmill is in the active status.

Contributing

Pull requests are welcome! Do your best to emulate the code around what you are editing.

Thank you!

If this works for you and improves your running experience, please consider donating to the developer who made this possible.

https://venmo.com/DawsonToth

This will also encourage future improvements. Thanks!

zwifit's People

Contributors

dawsontoth avatar dependabot[bot] avatar justintoth avatar raspelikan avatar stevehine avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zwifit's Issues

Proform 6.0 Sport Treadmill - Pi3 - Stuck at Retrieving information

Describe the bug
Stuck at "retrieving information from treadmill 6/7"

To Reproduce
Steps to reproduce the behavior:

  1. Setup following instructions on p3 (note, Node.JS is ver 15.3.0)
  2. Ran NPM Install from Zwifit folder
  3. Ran NPM start, got the following:
`Welcome to Zwifit!
Do you want to use metric units (KPH)? (Answer Y or N) n
Is your treadmill Bluetooth (Y) or WIFI (N) based? (Answer Y or N) y
Switch on your treadmill, press the connect button and enter the code shown on the display 6f85
Now you need to call "npm run enable-ble" to get access to your
Bluetooth equipment by using the treadmill's manufactor's app...

`
4. ran npm run enable-ble, and get:

> [email protected] enable-ble
> node src/ble/enable.js

Turn on your treadmill!
Found treadmill name with code 6f85 and name I_TL
(node:3005) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
Connected to treadmill...
Discovered all treadmill services...
Retrieving information from treadmill...
1/7
2/7
3/7
4/7
5/7
6/7

Let it sit for a while (5-15min) - no result. sudo restart doesn't fix. web UI never loads either.

Curious if I setup wrong.

Expected behavior
Imagine if run correctly it'd pair and let me connect w/ zwift

Screenshots
attached
ss

Crash when connecting with Garmin Fenix 5

Description
While trying to connect zwifit (connected with Proform 995i via BLE) with a Garmin Fenix 5 got a crash on the zwifit app.
This would be useful to perform a Garmin Coach training plan workout.

Steps To Reproduce

  1. Connect the treadmill with Zwifit via BLE
  2. Activate the Run-Speed-Cadence profile
  3. In the watch add zwifit as a sensor
  4. Start a treadmill activity
  5. Zwifit crash

Expected behavior
Should work as with zwift

Logs
0|app | Connected to Zwift (watch MAC address)
0|app | RangeError [ERR_OUT_OF_RANGE]: The value of "offset" is out of range. It must be >= 0 and <= 3. Received 4
0|app | at boundsError (internal/buffer.js:77:9)
0|app | at Buffer.readUInt8 (internal/buffer.js:243:5)
0|app | at parseCommandHeader (/home/pi/zwifit/src/ble/ifit/_request.js:707:29)
0|app | at /home/pi/zwifit/src/ble/ifit/_request.js:166:18
0|app | at Characteristic.listener (/home/pi/zwifit/src/ble/ifit/_request.js:657:4)
0|app | at Characteristic.emit (events.js:327:22)
0|app | at Noble.onRead (/home/pi/zwifit/node_modules/noble/lib/noble.js:414:20)
0|app | at NobleBindings.emit (events.js:315:20)
0|app | at NobleBindings.onNotification (/home/pi/zwifit/node_modules/noble/lib/hci-socket/bindings.js:448:8)
0|app | at Gatt.emit (events.js:315:20) {
0|app | code: 'ERR_OUT_OF_RANGE'
0|app | }

Debug
Added printing to the buffer:
0|app | writeRequestAndGatherResponse: 4
0|app | writeRequestAndGatherResponse: <Buffer 01 00 00 00>

So tried to discard packets with size <= 4 (is set to <4 only)
https://github.com/dawsontoth/zwifit/blob/master/src/ble/ifit/_request.js#L698

But started to get random disconnects from treadmill as soon as the activity on the watch starts

Functionality question for ifit proxy

I am attempting to build an iFit emulator to be used as a gateway between Concept2 Erg and iFit application. My understanding is zwifit is emulating ifit application to talk to physical device - is ifit protocol for discovery and connection is well understood to attempt this revered functionality?

Zwifit Frontend and Zwifit-incline-tracker incline control not working

Describe the bug
Zwifit is unable to control treadmill incline until a random time (20+ minutes) after the treadmill is started. I'm trying to work out how to switch my (Proform Pro 1000) into mode 2 (control mode) where the treadmill can be controlled by Zwifit.

When I say mode 2, I've seen it enter this mode via Zwifit debug code I've added when I was lucky enough to enter this mode. This allows the treadmill to be controlled, so I'm calling it control mode (a bad name for it I know).

This functionality is required so that the Zwifit Frontend and Zwifit-incliner can control the incline. The treadmill eventually switches to this mode, making a series of tones. Does Zwifit instruct the treadmill to enter mode 2 (control mode), or does the treadmill tell Zwifit that it can now be controlled?

To Reproduce
Mode 0: Initial state when searching for the treadmill
Mode 1: Treadmill power turned off
Mode 8: Treadmill power turned on. Key not plugged it. Display off. ifit light on.
Mode 1: Treadmill key inserted after being in state 8
Mode 10: Treadmill started
Mode 2: Expect control mode to be entered here.
Mode 3: Treadmill stopped
Mode 8: Key removed

Mode 2 (control mode) when the treadmill can be controlled by Zwifit, seems to occur randomly after 20 minutes or so. So randomly that I'm having problems going into this mode as I type this up. Until this mode is in operation, changes in speed, Incline, etc made on the treadmill are seen by Zwifit.

Expected behavior
When Zwifit makes a connection with the treadmill, entering mode 10, it should then switch to allow control of the treadmill so that both monitoring and control are possible.

Screenshots
N/A

Desktop (please complete the following information):
Raspbian, Zwifit, Treadmill

Additional context

None

Incline can't be set to 0%

Describe the bug
Either in the frontend, or in my case a simple test Android App, setting a control message where incline is set to 0 results in:
newIncline == undefined
This is in the controlRequested() fuction in the file: ./src/ble/ifit/index.js

To Reproduce
In the frontend, increase the incline, wait for the treadmill to reach the set incline value, then set it to 0%. Nothing will happen.

Expected behavior
When the control message has incline=0, it should set the incline to 0%

Screenshots
None, as it is easy to reproduce.

Desktop (please complete the following information):
Tested in Chrome, Firefox, and also an Android App written in MIT App Inventor 2

Additional context
My workaround in my basic app is to set an incline of -1 whenever I want to set the incline to 0. The current Zwifit code will automatically see that this is lower than 0 and set the incline to 0. I've tested this via debug in my code, but I haven't tested it on my treadmill as I'm having problems switching into control mode

After running npm run enable-ble what next?

Hi, in your instructions, it says run:

npm start

Then I'm asked to enter:
npm run enable-ble

It then says: turn on your Treadmill

But what next?! I've turned on the treadmill (new NordicTrack with iFit) but then nothing happens.

Anyway to trouble fix? I can't see the web server on my IP address either.. does that come up at a later stage? or should it already be running when I've run the above commands?

Thanks for any help

Connect to Aws IOT

I have a treadmill that has only Bluetooth with if I'm finishing a module in esp32 has access to the information of the treadmill and is record online Aws IOT. Can you make a feature that does not ask the ip but a complete url? and what is the JSON format expected by the endpoint? Do you have an example for me to copy? Thank you

Route Instructions

Hi,
First off, this program is amazing.
I was wondering if you could explain how to use the Routes functionality. It looks like a really powerful feature.
I assume that I shouldn't be connected to Zwift at the same time? I should only be connected to my Proform Pro 1000 via the iFit connection (which works really well with your software).
I can create routes using the text line examples provided, but in the Routes page I only see options to Edit or Delete them. I can't see how to Start them.
Please could you also explain how the "Recording Steps".
Thanks

issue releasing bluetooth daemon service

Describe the bug
in raspberry 4b the bluetooth daemon disabling using sudo systemctl disable bluetooth
does not release the resource to be used by hciconfig

To Reproduce
Steps to reproduce the behavior:

  1. sudo systemctl disable bluetooth
  2. systemctl status bluetooth.service
  3. observe the UP RUNNING status

Expected behavior
in step 3 expecting to see DOWN

Desktop (please complete the following information):

  • OS: raspbian
  • Version 5.4.79

Additional context
looks like the stopping alone still keeps the daemon, but these steps resolved the issue for me:

  • sudo systemctl stop bluetooth.service
  • sudo systemctl disable bluetooth.service
    to check:
  • systemctl status bluetooth.service or hciconfig hci0

CurrentKPH 0 for BLE treadmill

Zwifit fails to read the current KPH from my iFit treadmill (Proform 375) - CurrentKPH is always 0, everything else appears to function ok.

How can I debug this? Is there a way to see the raw treadmill data?

Thank you.

Improvements on instant readings

Managed to make this work on a Proform 995i
So for starters, thanks for awesome work!

Things I noticed:

  • my tradmill bluetooth code has a capitalized letter, if I put it like that software doesn't find the treadmill, so it would better to convert it to lower case to avoid this try/fail.

  • the main one for this feature request - some kind of rolling average that can attenuate the instant variations of speed.
    E.g. while trying to run at 11kph the reported speed on average was 10.7/10.8 I guess, but the variations were many and much frequent. And went like 10.5 to 11.5.. several times per second I would say.
    So some kind of rolling average of the last second / 2 seconds could smooth things a lot here.
    Would this be possible?

Proform Pro 5000

Has the solution been tested on Proform Pro 5000 treadmills (current model)? I'm looking to use this on a Raspberry Pi, it would be good to know if there has been success on this model?

DeprecationWarning

Hello,

I have the problem when I : "sudo npm start"
Failed at the [email protected] start script

This probably not.a problem with npm. There is likely additional logging output above

Is there something to do ?

Pro-form trainer 8.0

Thanks for this great tool!
I'm trying to get my Pro-form trainer 8.0 treadmill connected to my Pi, but am only partly successful. All the BT connection stuff seems to work fine, but I don't see any speed information on the 1337 site, it just shows 0. Incline works fine...
Any ideas how to fix this?

Issue with ProForm Hybrid Trainer

Installed everything on my RPI 3B+, no issues there. When running, I see

i@raspberrypi:~/zwifit $ npm run enable-ble

[email protected] enable-ble /home/pi/zwifit
node src/ble/enable.js

Turn on your treadmill!
Found treadmill name with code f3b6 and name 3815_Ifit_Bike
(node:7554) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use node --trace-deprecation ... to show where the warning was created)
Connected to treadmill...
Discovered all treadmill services...
Retrieving information from treadmill...
1/7
Trace: ERROR: checksum invalid
at processPeripheralError (/home/pi/zwifit/src/ble/enable.js:68:10)
at /home/pi/zwifit/src/ble/enable.js:177:4
at /home/pi/zwifit/src/ble/ifit/_request.js:228:4
at reportError (/home/pi/zwifit/src/ble/ifit/_request.js:666:3)
at Characteristic.listener (/home/pi/zwifit/src/ble/ifit/_request.js:654:6)
at Characteristic.emit (events.js:315:20)
at Noble.onRead (/home/pi/zwifit/node_modules/noble/lib/noble.js:414:20)
at NobleBindings.emit (events.js:315:20)
at NobleBindings.onNotification (/home/pi/zwifit/node_modules/noble/lib/hci-socket/bindings.js:448:8)
at Gatt.emit (events.js:315:20)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] enable-ble: node src/ble/enable.js
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] enable-ble script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /home/pi/.npm/_logs/2020-08-25T16_09_52_364Z-debug.log
2020-08-25T16_09_52_364Z-debug.log

Log attached. Is it just not compatible?

Route editing bugs

** Bug **
When I create a Route (route 1), and save it, it appears in the Routes list.
When I click the Edit button next to (route 1), the Route appears but with no name or configuration is shown.
When I create a 2nd Route (route 2), save it, it appears in the Routes list.
When I click the edit button for (route 2), it shows the name and configuration for (route 1).

However, When I create (route 3) and (route 4) these new route configurations are stored as expected.

To Reproduce
Follow the steps above

Expected behaviour
When the first (route 1) is created and then edited, the Route's name and configuration should be displayed and contain the details for (route 1).
When the 2nd (route 2) is created and then edited, it should show its own name and configuration.

Screenshots
Can be provided if requested.

Hardware

  • OS: Raspbian 10 Buster
  • Chromium
  • Version [e.g. 22]

Additional context
I'm running Swifit on a Proform Pro 1000 successfully.

Question: Does this run on MacOS Catalina?

The docs say it won't work on Mojave, I'm guessing the answer to Catalina is the same but wanted to be sure.

If so, what is the specific issue with Mojave / Catalina support, maybe I can help fix this and provide a PR?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.