Skip to content

Commit

Permalink
'cleanup' lol
Browse files Browse the repository at this point in the history
  • Loading branch information
Slinger360 committed Dec 18, 2019
1 parent 47253b2 commit e7321b9
Show file tree
Hide file tree
Showing 41 changed files with 1,233 additions and 1,286 deletions.
1 change: 1 addition & 0 deletions .android
12 changes: 10 additions & 2 deletions .gitignore
Expand Up @@ -15,8 +15,8 @@ __pycache__/
.idea/
bin/
build/
develop-eggs/
.buildozer/
develop-eggs/
dist/
downloads/
eggs/
Expand All @@ -36,7 +36,7 @@ MANIFEST
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
.spec

# Installer logs
pip-log.txt
Expand Down Expand Up @@ -109,3 +109,11 @@ venv.bak/

# mypy
.mypy_cache/

# JetBrains stuff
.idea/

.android/bin
.android/ndk
.android/sdk
/packaging/ninerift-1a.svg
6 changes: 6 additions & 0 deletions .gitmodules
@@ -0,0 +1,6 @@
[submodule ".android/able"]
path = .android/able
url = https://github.com/b3b/able
[submodule "vendor/py9b"]
path = vendor/py9b
url = https://github.com/Slinger360/py9b
49 changes: 49 additions & 0 deletions README
@@ -0,0 +1,49 @@
This is an Open-Source Ninebot and Xiaomi compatible scooter interface app.
THIS TOOL IS ONLY FOR USE ON DEVICES YOU OWN!!! It is still being added to but is in a functional state.


This application is written in Python3. To install required libraries, run the following two commands:

git clone --recursive https://github.com/slinger360/NineRiFt-kivy.git
pip install -r requirements.txt

To build for Android read up on Buildozer.

After that, you can either run NineRiFt on your Windows, Mac, or Linux machine by opening main.py using your Python3 interpreter or you can use a prebuilt APK for Android (you could also compile a build if you want).

On Android, BLE and TCP-Serial is supported.

On, Windows, Mac, and Linux, BLE, Serial, and TCP is supported.


The Download screen is for downloading firmware:

1. Select device you need firmware for in the dropdown on the left

2. Select the firmware version you need

3. Click "Download it!" and wait for download to complete


The Flash screen is for flashing firmware:

1. (Optional) Type the first few digits or the full length of the MAC address of the target scooter for flashing

2. Select the interface you want to use to connect (if wired, plug it in first)

3. Select the part you wish to flash

4. Select the firmware file you want flashed to the target scooter. DO NOT SELECT AN MD5 FILE!!! THIS IS NOT THE FIRMWARE!!!

5. Click "Flash it!" and wait for flashing to complete



At the moment only Segway-Ninebot SNSC, ES1, ES2, and ES4 and Xiaomi M365 and M365 Pro are supported.


SNSC dashboards cannot be flashed without either TCP-Serial or Serial interface.



If you appreciate my work, be sure to donate at https://PayPal.com/dilsha21 or any of the other options listed on my GitHub.
19 changes: 19 additions & 0 deletions changesn.kv
@@ -0,0 +1,19 @@
GridLayout:
cols: 1
rows: 2
GridLayout:
rows: 2
cols: 1
size_hint_y: .15
Label:
font_size: '12sp'
height: '12sp'
text: "NewSN:"
TextInput:
multiline: False
font_size: '12sp'
height: '12sp'
on_text_validate: app.com.setnewsn(self.text)
font_size: '12sp'
BoxLayout:
size_hint_y: .85
12 changes: 12 additions & 0 deletions dump.kv
@@ -0,0 +1,12 @@
GridLayout:
cols: 1
rows: 2
Spinner:
text: "Device"
font_size: '12sp'
height: '12sp'
size_hint_y: .15
values: ['esc','ble','bms','extbms']
on_text: app.com.setdev(self.text)
BoxLayout:
size_hint_y: .85
69 changes: 54 additions & 15 deletions fwget.py
@@ -1,9 +1,17 @@
import os
from os import path
import requests
from kivy.utils import platform
import hashlib
try:
from kivymd.toast import toast
except:
print('no toast for you')

# toast or print
def tprint(msg):
try:
toast(msg)
except:
print(msg)

class FWGet():
def __init__(self, cache):
Expand All @@ -12,7 +20,17 @@ def __init__(self, cache):
self.dirname = "null"
if not os.path.exists(self.cachePath):
os.makedirs(self.cachePath)
print("Created NineRiFt cache directory")
tprint("Created NineRiFt cache directory")
self.progress = 0
self.maxprogress = 100
self.model = ''
self.getboth = False
self.BLE = []
self.DRV = []
self.BMS = []

def setModel(self, model):
self.model = model

def setRepo(self, repo):
self.repoURL = repo
Expand All @@ -36,7 +54,7 @@ def md5Checksum(self, filePath, url):

def getFile(self, FWtype, version):
if (self.repoURL == "http://null" or self.dirname == "null"):
print("You need to load a valid repo first.")
tprint("You need to load a valid repo first.")
return(False)
noInternet = False
if not os.path.exists(self.cachePath + "/" + self.dirname + "/"):
Expand All @@ -46,11 +64,18 @@ def getFile(self, FWtype, version):
r = requests.head(self.repoURL)
if (r.status_code != 200):
noInternet = True
print("Failed to connect to the repo, using local files if available (Server response not 200)")
tprint("Failed to connect to the repo, using local files if available (Server response not 200)")
except requests.ConnectionError:
print("Failed to connect to the repo, using local files if available (requests.ConnectionError)")
tprint("Failed to connect to the repo, using local files if available (requests.ConnectionError)")
noInternet = True
filename = FWtype.upper() + version + ".bin.enc"
if self.model.startswith('m365'):
if FWtype is 'DRV' and self.getboth is False:
filename = FWtype.upper() + version + ".bin.enc"
self.getboth = True
else:
filename = FWtype.upper() + version + ".bin"
else:
filename = FWtype.upper() + version + ".bin.enc"
completePath = self.cachePath + "/" + self.dirname + "/" + filename
isFilePresent = os.path.isfile(completePath)
if noInternet == False:
Expand All @@ -73,9 +98,10 @@ def getFile(self, FWtype, version):
else:
url = self.repoURL + FWtype.lower() + "/" + filename
try:
print('download started')
r = requests.head(url)
if (r.status_code == 404):
print("Failed to fetch " + filename + " (Error 404 file not found)")
tprint("Failed to fetch " + filename + " (Error 404 file not found)")
return(False, completePath)
print('Beginning file download; writing to ' + completePath)
url = self.repoURL + FWtype.lower() + "/" + filename
Expand All @@ -85,25 +111,35 @@ def getFile(self, FWtype, version):
f.write(r.content)
if (r.status_code == 200):
print(filename + " downloaded successfully.")
print('download finished')
with open(completePath + ".md5", "r") as md5cached:
checksum = md5cached.read()
match = self.md5Checksum(completePath, None) == checksum
if not match:
if os.path.exists(completePath):
os.remove(completePath)
else:
print("The file does not exist")
tprint('File was corrupted. try again?')
return(True, completePath)
else:
print("Server couldn't respond to download request. Local files aren't available. Aborting.")
tprint("Server couldn't respond to download request. Local files aren't available. Aborting.")
return(False, completePath)
except requests.ConnectionError:
print("Connection error. Local files aren't available. Aborting.")
tprint("Connection error. Local files aren't available. Aborting.")
return(False, completePath)

def loadRepo(self, jsonURL):
d = ''
noInternet = False
hashedName = hashlib.md5(jsonURL).hexdigest()
hashedName = hashlib.md5(jsonURL.encode("utf-8")).hexdigest()
try:
r = requests.head(jsonURL)
if (r.status_code != 200):
noInternet = True
print("Failed to fetch JSON! Will use cached if available. (Server response not 200)")
tprint("Failed to fetch JSON! Will use cached if available. (Server response not 200)")
except requests.ConnectionError:
print("Failed to fetch JSON! Will use cached if available. (requests.ConnectionError)")
tprint("Failed to fetch JSON! Will use cached if available. (requests.ConnectionError)")
noInternet = True
if noInternet == False:
try:
Expand All @@ -114,15 +150,15 @@ def loadRepo(self, jsonURL):
d = eval(f.read())
print("Fetched repo JSON.")
except requests.ConnectionError:
print("Failed to grab JSON! (requests.ConnectionError)")
tprint("Failed to grab JSON! (requests.ConnectionError)")
return(False)

elif os.path.isfile(self.cachePath + hashedName + ".json"):
with open(self.cachePath + hashedName + ".json") as f:
d = eval(f.read())
print("Fetched cached repo JSON.")
else:
print("Couldn't download file and couldn't load from cache. Aborting.")
tprint("Couldn't download file and couldn't load from cache. Aborting.")
return(False)
self.dirname = str(d["repo"]["infos"]["dirname"])
self.repoURL = str(d["repo"]["infos"]["files_URL"])
Expand All @@ -135,4 +171,7 @@ def loadRepo(self, jsonURL):
return(True, self.dirname, self.repoURL, name, self.DRV, self.BMS, self.BLE)

def Gimme(self, firm, ver):
tprint('download started')
self.getFile(firm,ver)
self.getFile(firm, ver)
tprint('download finished')

0 comments on commit e7321b9

Please sign in to comment.