Compare commits

...

3 Commits

8 changed files with 414 additions and 132 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,8 @@
*.py[oc] *.py[oc]
*.swp *.swp
_buildid.py
build/ build/
dist/ dist/

View File

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>503</width> <width>493</width>
<height>530</height> <height>466</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@@ -17,7 +17,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Luftdaten.info Flashing Tool</string> <string>Luftdaten.info Flashing Tool (v{version})</string>
</property> </property>
<property name="windowIcon"> <property name="windowIcon">
<iconset> <iconset>
@@ -32,29 +32,62 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QToolBox" name="toolBox"> <widget class="QFrame" name="globalMessage">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="globalMessageTitle">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="globalMessageText">
<property name="text">
<string/>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="tabPosition">
<enum>QTabWidget::South</enum>
</property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="page_3"> <widget class="QWidget" name="programmingTab">
<property name="geometry">
<rect>
<x>0</x>
<y>-25</y>
<width>471</width>
<height>399</height>
</rect>
</property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<attribute name="label"> <attribute name="title">
<string>Programming</string> <string>Flashing</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2" rowstretch="0,0,0,0,0,0,0,1">
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
@@ -62,6 +95,66 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="2">
<widget class="QProgressBar" name="progressBar"/>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="versionBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="uploadButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Upload</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="expertModeBox">
<property name="text">
<string>Expert mode</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="boardBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Board:</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2"> <item row="7" column="0" colspan="2">
<widget class="QWidget" name="expertForm" native="true"> <widget class="QWidget" name="expertForm" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
@@ -101,98 +194,143 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="5" column="0" colspan="2"> </layout>
<widget class="QProgressBar" name="progressBar"/> </widget>
<widget class="QWidget" name="discoveryTab">
<attribute name="title">
<string>Discovery</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0" colspan="2">
<widget class="QListWidget" name="discoveryList"/>
</item> </item>
<item row="3" column="1"> <item row="4" column="0" colspan="2">
<widget class="QComboBox" name="versionBox"> <widget class="QLabel" name="label_5">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Double-click to open configuration page.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="editable"> <property name="text">
<string>Sensors detected in local network:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="discoveryRefreshButton">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="serialTab">
<attribute name="title">
<string>Serial Monitor</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="2" column="0">
<widget class="QTextEdit" name="serialTextEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>In case of sensor issues, Serial Monitor can be used to review logs sent by the sensor over USB cable.</string>
</property>
<property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Board:</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="uploadButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Upload</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="expertModeBox">
<property name="text">
<string>Expert mode</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="boardBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_4">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>491</width>
<height>374</height>
</rect>
</property>
<attribute name="label">
<string>Discovery</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0"> <item row="1" column="0">
<widget class="QListWidget" name="listWidget"/> <widget class="QPushButton" name="serialConnectButton">
</item>
<item row="2" column="0">
<widget class="QPushButton" name="pushButton">
<property name="text"> <property name="text">
<string>Scan</string> <string>Connect</string>
</property>
<property name="checkable">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="page_5"> <widget class="QWidget" name="aboutTab">
<attribute name="label"> <attribute name="title">
<string>About</string> <string>About</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout_3"/> <layout class="QGridLayout" name="gridLayout_3">
<property name="spacing">
<number>12</number>
</property>
<item row="1" column="1">
<widget class="QLabel" name="buildLabel">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>&lt;b&gt;Luftdaten.info Flashing Tool&lt;/b&gt;&lt;br/&gt;Build {build_id}</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="maximumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>../assets/logo.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Developed by &lt;a href=&quot;https://inf.re/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Piotr Dobrowolski&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This software is released under the terms of MIT license. No warranty is provided.&lt;/p&gt;&lt;p&gt;For newest release see: &lt;a href=&quot;https://d.inf.re/luftdaten/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://d.inf.re/luftdaten/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</widget> </widget>
</item> </item>
@@ -203,8 +341,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>503</width> <width>493</width>
<height>29</height> <height>20</height>
</rect> </rect>
</property> </property>
</widget> </widget>

View File

@@ -4,94 +4,149 @@
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../luftdaten-tool.py" line="199"/> <location filename="../luftdaten-tool.py" line="132"/>
<source>No boards found</source> <source>No boards found</source>
<translation>Nie znaleziono płytki</translation> <translation>Nie znaleziono płytki</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="204"/> <location filename="../luftdaten-tool.py" line="141"/>
<source>Others...</source> <source>Others...</source>
<translation>Inne...</translation> <translation>Inne...</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="233"/> <location filename="../luftdaten-tool.py" line="170"/>
<source>No device selected.</source> <source>No device selected.</source>
<translation>Nie wybrano urządzenia.</translation> <translation>Nie wybrano urządzenia.</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="237"/> <location filename="../luftdaten-tool.py" line="174"/>
<source>No version selected.</source> <source>No version selected.</source>
<translation>Nie wybrano wersji.</translation> <translation>Nie wybrano wersji.</translation>
</message> </message>
<message> <message>
<location filename="../gui/mainwindow.py" line="131"/> <location filename="../gui/mainwindow.py" line="226"/>
<source>Board:</source> <source>Board:</source>
<translation>Płytka:</translation> <translation>Płytka:</translation>
</message> </message>
<message> <message>
<location filename="../gui/mainwindow.py" line="132"/> <location filename="../gui/mainwindow.py" line="223"/>
<source>Firmware version:</source> <source>Firmware version:</source>
<translation>Wersja oprogramowania:</translation> <translation>Wersja oprogramowania:</translation>
</message> </message>
<message> <message>
<location filename="../gui/mainwindow.py" line="133"/> <location filename="../gui/mainwindow.py" line="224"/>
<source>Upload</source> <source>Upload</source>
<translation>Wgraj</translation> <translation>Wgraj</translation>
</message> </message>
<message> <message>
<location filename="../gui/mainwindow.py" line="134"/> <location filename="../gui/mainwindow.py" line="225"/>
<source>Expert mode</source> <source>Expert mode</source>
<translation>Tryb eksperta</translation> <translation>Tryb eksperta</translation>
</message> </message>
<message> <message>
<location filename="../gui/mainwindow.py" line="135"/> <location filename="../gui/mainwindow.py" line="227"/>
<source>Baudrate:</source> <source>Baudrate:</source>
<translation>Prędkość portu:</translation> <translation>Prędkość portu:</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="252"/> <location filename="../luftdaten-tool.py" line="189"/>
<source>Invalid version / file does not exist</source> <source>Invalid version / file does not exist</source>
<translation>Błędna wersja / plik nie istnieje</translation> <translation>Błędna wersja / plik nie istnieje</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="257"/> <location filename="../luftdaten-tool.py" line="194"/>
<source>Work in progess...</source> <source>Work in progess...</source>
<translation>Praca w toku...</translation> <translation>Praca w toku...</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="284"/> <location filename="../luftdaten-tool.py" line="221"/>
<source>Downloading...</source> <source>Downloading...</source>
<translation>Pobieranie...</translation> <translation>Pobieranie...</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="296"/> <location filename="../luftdaten-tool.py" line="231"/>
<source>Connecting...</source> <source>Connecting...</source>
<translation>Łączenie...</translation> <translation>Łączenie...</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="301"/> <location filename="../luftdaten-tool.py" line="236"/>
<source>Connected. Chip type: {chip_type}</source> <source>Connected. Chip type: {chip_type}</source>
<translation>Połączono. Typ układu: {chip_type}</translation> <translation>Połączono. Typ układu: {chip_type}</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="319"/> <location filename="../luftdaten-tool.py" line="254"/>
<source>Writing at 0x{address:08x}...</source> <source>Writing at 0x{address:08x}...</source>
<translation>Zapisywanie pod adresem 0x{address:08x}...</translation> <translation>Zapisywanie pod adresem 0x{address:08x}...</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="330"/> <location filename="../luftdaten-tool.py" line="265"/>
<source>Finished in {time:.2f} seconds. Sensor ID: {sensor_id}</source> <source>Finished in {time:.2f} seconds. Sensor ID: {sensor_id}</source>
<translation>Zakończono w {time:.2f} sekundy. ID sensora: {sensor_id}</translation> <translation>Zakończono w {time:.2f} sekundy. ID sensora: {sensor_id}</translation>
</message> </message>
<message> <message>
<location filename="../gui/mainwindow.py" line="130"/> <location filename="../gui/mainwindow.py" line="236"/>
<source>Luftdaten.info Flashing Tool</source> <source>Luftdaten.info Flashing Tool</source>
<translation>Luftdaten.info Flashing Tool</translation> <translation>Luftdaten.info Flashing Tool</translation>
</message> </message>
<message> <message>
<location filename="../luftdaten-tool.py" line="138"/> <location filename="../luftdaten-tool.py" line="52"/>
<source>Loading firmware list...</source> <source>Loading firmware list...</source>
<translation>Ładowanie wersji oprogramowania...</translation> <translation>Ładowanie wersji oprogramowania...</translation>
</message> </message>
<message>
<location filename="../luftdaten-tool.py" line="132"/>
<source>Have you installed &lt;a href=&quot;{drivers_url}&quot;&gt;the drivers&lt;/a&gt;?</source>
<translation>Czy zainstalowałeś &lt;a href=&quot;{drivers_url}&quot;&gt;sterowniki&lt;/a&gt;?</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="228"/>
<source>Flashing</source>
<translation>Programowanie</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="229"/>
<source>Double-click to open configuration page.</source>
<translation>Naciśnij dwukrotnie aby otworzyć stronę konfiguracji.</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="230"/>
<source>Sensors detected in local network:</source>
<translation>Sensory wykryte w sieci lokalnej:</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="231"/>
<source>Refresh</source>
<translation>Odśwież</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="232"/>
<source>Discovery</source>
<translation>Wykrywanie</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="233"/>
<source>In case of sensor issues, Serial Monitor can be used to review logs sent by the sensor over USB cable.</source>
<translation>W przypadku problemów z sensorem, Serial Monitor pozwala na przejrzenie stanu urządzenia przez kabel USB.</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="234"/>
<source>Connect</source>
<translation>Połącz</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="235"/>
<source>Serial Monitor</source>
<translation>Serial Monitor</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="237"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Developed by &lt;a href=&quot;https://inf.re/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Piotr Dobrowolski&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This software is released under the terms of MIT license. No warranty is provided.&lt;/p&gt;&lt;p&gt;For newest release see: &lt;a href=&quot;https://d.inf.re/luftdaten/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://d.inf.re/luftdaten/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Wykonane przez &lt;a href=&quot;https://inf.re/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Piotr Dobrowolski&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Ten program wypuszczony jest na warunkach licencji MIT. Brak gwarancji.&lt;/p&gt;&lt;p&gt;Najnowszą wersję znajdziesz na: &lt;a href=&quot;https://d.inf.re/luftdaten/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://d.inf.re/luftdaten/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>
<location filename="../gui/mainwindow.py" line="238"/>
<source>About</source>
<translation>O programie</translation>
</message>
</context> </context>
</TS> </TS>

View File

@@ -11,6 +11,7 @@ import logging
import requests import requests
from esptool import ESPLoader from esptool import ESPLoader
import luftdatentool
from luftdatentool.qtvariant import QtGui, QtCore, QtWidgets from luftdatentool.qtvariant import QtGui, QtCore, QtWidgets
from luftdatentool.utils import QuickThread from luftdatentool.utils import QuickThread
from luftdatentool.workers import PortDetectThread, FirmwareListThread, \ from luftdatentool.workers import PortDetectThread, FirmwareListThread, \
@@ -19,7 +20,7 @@ from luftdatentool.workers import PortDetectThread, FirmwareListThread, \
from gui import mainwindow from gui import mainwindow
from luftdatentool.consts import UPDATE_REPOSITORY, ALLOWED_PROTO, \ from luftdatentool.consts import UPDATE_REPOSITORY, ALLOWED_PROTO, \
PREFERED_PORTS, ROLE_DEVICE PREFERED_PORTS, ROLE_DEVICE, DRIVERS_URL
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
RESOURCES_PATH = sys._MEIPASS RESOURCES_PATH = sys._MEIPASS
@@ -31,6 +32,8 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
uploadProgress = QtCore.Signal([str, int]) uploadProgress = QtCore.Signal([str, int])
errorSignal = QtCore.Signal([str]) errorSignal = QtCore.Signal([str])
uploadThread = None uploadThread = None
zeroconf_discovery = None
boards_detected = False
def __init__(self, parent=None, app=None): def __init__(self, parent=None, app=None):
super(MainWindow, self).__init__(parent) super(MainWindow, self).__init__(parent)
@@ -43,8 +46,8 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
os.chdir(oldcwd) os.chdir(oldcwd)
self.app = app self.app = app
self.translator = QtCore.QTranslator()
self.translator = QtCore.QTranslator()
self.i18n_init(QtCore.QLocale.system()) self.i18n_init(QtCore.QLocale.system())
self.statusbar.showMessage(self.tr("Loading firmware list...")) self.statusbar.showMessage(self.tr("Loading firmware list..."))
@@ -59,18 +62,25 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.port_detect.error.connect(self.on_work_error) self.port_detect.error.connect(self.on_work_error)
self.port_detect.start() self.port_detect.start()
self.zeroconf_discovery = ZeroconfDiscoveryThread() self.discovery_start()
self.zeroconf_discovery.deviceDiscovered.connect(
self.on_zeroconf_discovered)
self.zeroconf_discovery.start()
self.globalMessage.hide()
# Hide WIP GUI parts...
self.on_expertModeBox_clicked() self.on_expertModeBox_clicked()
self.expertModeBox.hide()
self.tabWidget.removeTab(self.tabWidget.indexOf(self.serialTab))
self.uploadProgress.connect(self.on_work_update) self.uploadProgress.connect(self.on_work_update)
self.errorSignal.connect(self.on_work_error) self.errorSignal.connect(self.on_work_error)
self.cachedir = tempfile.TemporaryDirectory() self.cachedir = tempfile.TemporaryDirectory()
def show_global_message(self, title, message):
self.globalMessage.show()
self.globalMessageTitle.setText(title)
self.globalMessageText.setText(message)
def on_work_update(self, status, progress): def on_work_update(self, status, progress):
self.statusbar.showMessage(status) self.statusbar.showMessage(status)
self.progressBar.setValue(progress) self.progressBar.setValue(progress)
@@ -78,16 +88,20 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
def on_work_error(self, message): def on_work_error(self, message):
self.statusbar.showMessage(message) self.statusbar.showMessage(message)
def on_zeroconf_discovered(self, name, address, info): @property
"""Called on every zeroconf discovered device""" def version(self):
if name.startswith('Feinstaubsensor'): return luftdatentool.__version__
item = QtWidgets.QListWidgetItem('{}: {}'.format(address, name.split('.')[0]))
item.setData(ROLE_DEVICE, 'http://{}:{}'.format(address, info.port))
self.listWidget.addItem(item)
@QtCore.Slot(QtWidgets.QListWidgetItem) @property
def on_listWidget_itemDoubleClicked(self, index): def build_id(self):
QtGui.QDesktopServices.openUrl(QtCore.QUrl(index.data(ROLE_DEVICE))) try:
from luftdatentool._buildid import commit, builddate
except ImportError:
import datetime
commit = 'devel'
builddate = datetime.datetime.now().strftime('%Y%m%d')
return '{}-{}/{}'.format(self.version, commit, builddate)
def i18n_init(self, locale): def i18n_init(self, locale):
"""Initializes i18n to specified QLocale""" """Initializes i18n to specified QLocale"""
@@ -99,6 +113,13 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
self.app.installTranslator(self.translator) self.app.installTranslator(self.translator)
self.retranslateUi(self) self.retranslateUi(self)
def retranslateUi(self, win):
super(MainWindow, self).retranslateUi(win)
win.setWindowTitle(win.windowTitle().format(
version=self.version))
win.buildLabel.setText(win.buildLabel.text().format(
build_id=self.build_id))
def populate_versions(self, files): def populate_versions(self, files):
"""Loads available firmware versions into versionbox widget""" """Loads available firmware versions into versionbox widget"""
@@ -131,6 +152,17 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
sep.setEnabled(False) sep.setEnabled(False)
self.boardBox.model().appendRow(sep) self.boardBox.model().appendRow(sep)
# No prefered boards has been found so far and there is a
# suggested driver download URL available
if not self.boards_detected and DRIVERS_URL:
self.show_global_message(
self.tr('No boards found'),
self.tr('Have you installed <a href="{drivers_url}">'
'the drivers</a>?').format(drivers_url=DRIVERS_URL))
else:
self.globalMessage.hide()
self.boards_detected = True
if others: if others:
sep = QtGui.QStandardItem(self.tr('Others...')) sep = QtGui.QStandardItem(self.tr('Others...'))
sep.setEnabled(False) sep.setEnabled(False)
@@ -263,9 +295,36 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
@QtCore.Slot() @QtCore.Slot()
def on_expertModeBox_clicked(self): def on_expertModeBox_clicked(self):
self.expertForm.setVisible(self.expertModeBox.checkState()) self.expertForm.setVisible(self.expertModeBox.checkState())
self.centralwidget.setFixedHeight( #self.centralwidget.setFixedHeight(
self.centralwidget.sizeHint().height()) # self.centralwidget.sizeHint().height())
self.setFixedHeight(self.sizeHint().height()) #self.setFixedHeight(self.sizeHint().height())
# Zeroconf page
def discovery_start(self):
if self.zeroconf_discovery:
self.zeroconf_discovery.stop()
self.zeroconf_discovery = ZeroconfDiscoveryThread()
self.zeroconf_discovery.deviceDiscovered.connect(
self.on_zeroconf_discovered)
self.zeroconf_discovery.start()
def on_zeroconf_discovered(self, name, address, info):
"""Called on every zeroconf discovered device"""
if name.startswith('Feinstaubsensor'):
item = QtWidgets.QListWidgetItem('{}: {}'.format(address, name.split('.')[0]))
item.setData(ROLE_DEVICE, 'http://{}:{}'.format(address, info.port))
self.discoveryList.addItem(item)
@QtCore.Slot(QtWidgets.QListWidgetItem)
def on_discoveryList_itemDoubleClicked(self, index):
QtGui.QDesktopServices.openUrl(QtCore.QUrl(index.data(ROLE_DEVICE)))
@QtCore.Slot()
def on_discoveryRefreshButton_clicked(self):
self.discoveryList.clear()
self.discovery_start()
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -2,6 +2,16 @@
block_cipher = None block_cipher = None
import subprocess
import datetime
commit = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).strip().decode('utf-8')
builddate = datetime.datetime.now().strftime('%Y%m%d')
with open('luftdatentool/_buildid.py', 'w') as fd:
fd.write('''# This file is autogenerated in luftdaten-tool.spec file
commit = "{commit}"
builddate = "{builddate}"'''.format(commit=commit, builddate=builddate))
a = Analysis(['luftdaten-tool.py'], a = Analysis(['luftdaten-tool.py'],
pathex=['.'], pathex=['.'],

View File

@@ -0,0 +1 @@
__version__ = '0.2'

View File

@@ -1,5 +1,8 @@
import sys
from .qtvariant import QtCore from .qtvariant import QtCore
# Firmware update repository # Firmware update repository
UPDATE_REPOSITORY = 'https://www.madavi.de/sensor/update/data/' UPDATE_REPOSITORY = 'https://www.madavi.de/sensor/update/data/'
@@ -16,3 +19,10 @@ PREFERED_PORTS = [
] ]
ROLE_DEVICE = QtCore.Qt.UserRole + 1 ROLE_DEVICE = QtCore.Qt.UserRole + 1
if sys.platform.startswith('darwin'):
DRIVERS_URL = 'http://www.wch.cn/downloads/CH341SER_MAC_ZIP.html'
elif sys.platform.startswith(('cygwin', 'win32')):
DRIVERS_URL = 'http://www.wch.cn/downloads/CH341SER_ZIP.html'
else:
DRIVERS_URL = None

View File

@@ -17,11 +17,11 @@ class PortDetectThread(QuickThread):
def target(self): def target(self):
"""Checks list of available ports and emits signal when necessary""" """Checks list of available ports and emits signal when necessary"""
ports = [] ports = None
while True: while True:
new_ports = serial.tools.list_ports.comports() new_ports = serial.tools.list_ports.comports()
if [p.name for p in ports] != [p.name for p in new_ports]: if ports is None or [p.name for p in ports] != [p.name for p in new_ports]:
self.portsUpdate.emit(new_ports) self.portsUpdate.emit(new_ports)
time.sleep(self.interval) time.sleep(self.interval)
@@ -39,10 +39,13 @@ class FirmwareListThread(QuickThread):
class ZeroconfDiscoveryThread(QuickThread): class ZeroconfDiscoveryThread(QuickThread):
deviceDiscovered = QtCore.Signal(str, str, object) deviceDiscovered = QtCore.Signal(str, str, object)
browser = None
def target(self): def target(self):
zc = zeroconf.Zeroconf() """This thread scans for Bonjour/mDNS devices and emits
browser = zeroconf.ServiceBrowser(zc, "_http._tcp.local.", deviceDiscovered signal with its name, address and info object"""
self.zc = zeroconf.Zeroconf()
self.browser = zeroconf.ServiceBrowser(self.zc, "_http._tcp.local.",
handlers=[self.on_state_change]) handlers=[self.on_state_change])
while True: while True:
time.sleep(0.5) time.sleep(0.5)
@@ -51,3 +54,7 @@ class ZeroconfDiscoveryThread(QuickThread):
info = zeroconf.get_service_info(service_type, name) info = zeroconf.get_service_info(service_type, name)
if info: if info:
self.deviceDiscovered.emit(name, socket.inet_ntoa(info.address), info) self.deviceDiscovered.emit(name, socket.inet_ntoa(info.address), info)
def stop(self):
if self.browser:
self.browser.cancel()