-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite to normal websockets, add support for Windows and add a GUI m…
…ode, to ultimately replace JulianaNFC_C
- Loading branch information
Showing
12 changed files
with
512 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,55 @@ | ||
# JulianaNFC | ||
JulianaNFC is een Python-programmaatje dat pollt voor NFC tags en deze vervolgens over een WebSocket verstuurt. Werkt alleen onder Linux voor zover bekend. | ||
JulianaNFC is een Python-programmaatje voor Windows en Linux dat pollt voor NFC tags en deze vervolgens over een WebSocket verstuurt. | ||
|
||
## Hoe dan? | ||
Installeer onder Linux de PC/SC Smart Card daemon ( [PCSClite](https://pcsclite.alioth.debian.org/pcsclite.html) - [Debian PKG](https://packages.debian.org/source/stretch/pcsc-lite) ) en zorg dat deze gestart is. Installeer de requirements uit requirements.txt en start juliana.py. Vanuit een browser connect je met de WebSocket. | ||
|
||
socket = new WebSocket("ws://localhost:3000", "nfc"); | ||
### Windows | ||
Geen requirements, Windows heeft een ingebouwde PC/SC Smart Card service. | ||
|
||
Als er een kaart wordt gescand ontvang je een JSON-object met kaartinfo over de socket. | ||
- Download de [release executable](https://github.com/Inter-Actief/JulianaNFC_Python/releases) voor Windows (`JulianaNFC_vX.X.exe`) | ||
- Zet hem op een mooi plekje neer | ||
- Start daarna `JulianaNFC_vX.X.exe`, de GUI zal starten. | ||
|
||
{"atqa":"12:34", "uid":"ab:cd:ef:gh", "sak":"56"} | ||
### Linux | ||
|
||
#### Requirements | ||
Installeer onder Linux de PC/SC Smart Card daemon ( [PCSClite](https://pcsclite.alioth.debian.org/pcsclite.html) - [Debian PKG](https://packages.debian.org/source/stretch/pcsc-lite) ) en zorg dat deze gestart is. | ||
|
||
#### JulianaNFC - Optie 1 | ||
- Download de [release executable](https://github.com/Inter-Actief/JulianaNFC_Python/releases) voor Linux (`JulianaNFC_linux_vX.X`) | ||
- Zet hem op een mooi plekje neer | ||
- Start het executable bestand `JulianaNFC_linux_vX.X`, de GUI zal starten. (draai het met de `-h` flag voor CLI-opties) | ||
|
||
#### JulianaNFC - Optie 2 | ||
- Clone of download de code van github | ||
- Maak een virtualenv als je dat graag wilt | ||
- Installeer de requirements uit requirements.txt | ||
- Voer `python juliana.py` uit, de GUI zal starten. (zie `juliana.py -h` voor CLI-opties) | ||
|
||
### Websocket | ||
Vanuit een browser connect je met de WebSocket. | ||
|
||
socket = new WebSocket('ws://localhost:3000', 'nfc'); | ||
socket.onmessage = function (event) { | ||
var rfid = JSON.parse(event.data); | ||
console.log("Tag scanned!"); | ||
console.log(rfid); | ||
}; | ||
|
||
Als er een kaart wordt gescand ontvang je in het 'nfc_read' event een JSON-object met kaartinfo over de socket. | ||
|
||
{"type": "iso-x", "atqa":"12:34", "uid":"ab:cd:ef:gh", "sak":"56"} | ||
|
||
En dat is alles wat JulianaNFC doet. | ||
|
||
## Bugs en to-do's | ||
Bij het scannen van sommige kaarten (i.e. ID-kaarten) breekt de NFC lezer (onder Linux). Even de lezer opnieuw inpluggen fixt het dan vaak. | ||
|
||
WebSockets zijn zéér gebrekkig geïmplementeerd. Zodra iets niet volgens plan gebeurt crasht JulianaNFC. | ||
## Package bouwen | ||
- Zoek een computer met het gewenste doelbesturingssysteem en installeer Python en alle requirements voor JulianaNFC. | ||
- Noot: Gebruik bij packagen op Windows een python-versie waarvoor een [.whl van wxPython](https://pypi.org/project/wxPython/#files) beschikbaar is, dit package zelf bouwen op Windows is lastig. | ||
- Installeer pyinstaller (`pip install pyinstaller`) (Getest met 5.2, maar zou met nieuwere prima moeten werken) | ||
- Open een command prompt / terminal en ga naar de map waar JulianaNFC staat | ||
- Verwijder de `build` en `dist` folders als deze nog bestaan van een vorige build | ||
- Draai Pyinstaller op de specfile (`pyinstaller juliana_nfc.spec`) | ||
- De build zal in de `build` folder plaatsvinden, de executable zal in de `dist` folder geplaatst worden. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import wx | ||
import wx.adv | ||
|
||
from juliana import resource_path | ||
|
||
class AboutDialog(wx.Dialog): | ||
def __init__(self, *args, **kwargs): | ||
from juliana import APP_SUPPORT, APP_LINK | ||
kwargs["style"] = kwargs.get("style", 0) | wx.DEFAULT_DIALOG_STYLE | ||
wx.Dialog.__init__(self, *args, **kwargs) | ||
self.SetSize((400, 350)) | ||
self.SetIcon(wx.Icon(resource_path("resources/main.png"), type=wx.BITMAP_TYPE_PNG)) | ||
self.hyperlink_2 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, APP_LINK, APP_LINK, style=wx.adv.HL_ALIGN_CENTRE) | ||
self.hyperlink_3 = wx.adv.HyperlinkCtrl(self, wx.ID_ANY, APP_SUPPORT, f"mailto://{APP_SUPPORT}", style=wx.adv.HL_ALIGN_CENTRE) | ||
self.button_2 = wx.Button(self, wx.ID_OK, "") | ||
|
||
self.__set_properties() | ||
self.__do_layout() | ||
|
||
def __set_properties(self): | ||
self.SetTitle(f"About JulianaNFC") | ||
self.SetSize((400, 350)) | ||
|
||
def __do_layout(self): | ||
from juliana import APP_NAME, APP_VERSION, APP_AUTHOR | ||
grid_sizer_1 = wx.BoxSizer(wx.VERTICAL) | ||
grid_sizer_1.Add((0, 10), 0, wx.EXPAND, 0) | ||
label_1 = wx.StaticText(self, wx.ID_ANY, f"{APP_NAME} v{APP_VERSION}", style=wx.ALIGN_CENTER) | ||
label_1.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, 0, "")) | ||
grid_sizer_1.Add(label_1, 0, wx.ALIGN_CENTER, 8) | ||
grid_sizer_1.Add((0, 8), 0, wx.EXPAND, 0) | ||
static_line_1 = wx.StaticLine(self, wx.ID_ANY) | ||
grid_sizer_1.Add(static_line_1, 0, wx.ALL | wx.EXPAND, 0) | ||
grid_sizer_1.Add((0, 8), 0, wx.EXPAND, 0) | ||
label_2 = wx.StaticText(self, wx.ID_ANY, f"JulianaNFC is a small tray application that allows scanning " | ||
f"NFC cards to a websocket for use in web applications.", style=wx.ALIGN_CENTER) | ||
label_2.Wrap(320) | ||
grid_sizer_1.Add(label_2, 0, wx.ALIGN_CENTER, 8) | ||
grid_sizer_1.Add((0, 8), 0, wx.EXPAND, 0) | ||
label_3 = wx.StaticText(self, wx.ID_ANY, f"JulianaNFC was created by {APP_AUTHOR}", style=wx.ALIGN_CENTER) | ||
label_3.Wrap(320) | ||
grid_sizer_1.Add(label_3, 0, wx.ALIGN_CENTER, 8) | ||
grid_sizer_1.Add((0, 8), 0, wx.EXPAND, 0) | ||
label_6 = wx.StaticText(self, wx.ID_ANY, "For more information, check the GitHub:", style=wx.ALIGN_CENTER) | ||
grid_sizer_1.Add(label_6, 0, wx.ALIGN_CENTER, 0) | ||
grid_sizer_1.Add(self.hyperlink_2, 0, wx.ALIGN_CENTER, 0) | ||
label_7 = wx.StaticText(self, wx.ID_ANY, "For support, mail the WWW-committee:", style=wx.ALIGN_CENTER) | ||
grid_sizer_1.Add(label_7, 0, wx.ALIGN_CENTER, 0) | ||
grid_sizer_1.Add(self.hyperlink_3, 0, wx.ALIGN_CENTER, 0) | ||
grid_sizer_1.Add((0, 10), 0, wx.EXPAND, 0) | ||
grid_sizer_1.Add(self.button_2, 0, wx.ALIGN_CENTER, 0) | ||
grid_sizer_1.Add((0, 10), 0, wx.EXPAND, 0) | ||
self.SetSizer(grid_sizer_1) | ||
grid_sizer_1.Fit(self) | ||
self.Layout() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import wx | ||
import wx.adv | ||
import signal | ||
import os | ||
import time | ||
import logging | ||
|
||
from juliana import resource_path | ||
|
||
|
||
logging.basicConfig(level=logging.INFO) | ||
|
||
|
||
class JulianaTrayIcon(wx.adv.TaskBarIcon): | ||
def __init__(self, frame): | ||
self.frame = frame | ||
super(JulianaTrayIcon, self).__init__() | ||
self.SetIcon(wx.Icon(resource_path("resources/main.png"), type=wx.BITMAP_TYPE_PNG), "JulianaNFC") | ||
self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_click) | ||
|
||
def CreatePopupMenu(self): | ||
self.menu = wx.Menu() | ||
self.create_menu_text(self.menu, "JulianaNFC") | ||
self.menu.AppendSeparator() | ||
self.create_menu_item(self.menu, "About", self.on_about) | ||
self.create_menu_item(self.menu, "Exit", self.on_exit) | ||
return self.menu | ||
|
||
def create_menu_item(self, menu, label, callback, icon=None): | ||
item = wx.MenuItem(menu, -1, label) | ||
menu.Bind(wx.EVT_MENU, callback, id=item.GetId()) | ||
menu.Append(item) | ||
if icon is not None: | ||
bitmap = wx.Bitmap(icon, type=wx.BITMAP_TYPE_PNG) | ||
item.SetBitmaps(checked=bitmap, unchecked=bitmap) | ||
return item | ||
|
||
def create_menu_text(self, menu, label, icon=None): | ||
item = wx.MenuItem(menu, -1, label) | ||
menu.Append(item) | ||
item.Enable(False) | ||
if icon is not None: | ||
bitmap = wx.Bitmap(icon, type=wx.BITMAP_TYPE_PNG) | ||
item.SetBitmaps(checked=bitmap, unchecked=bitmap) | ||
return item | ||
|
||
def on_left_click(self, event): | ||
if self.frame.IsShown(): | ||
logging.info("Tray icon was left-clicked. Hiding main window") | ||
self.frame.Show(False) | ||
else: | ||
logging.info("Tray icon was left-clicked. Showing main window") | ||
self.frame.Show(True) | ||
|
||
def on_about(self, event): | ||
logging.debug("Tray option about clicked.") | ||
from gui.about import AboutDialog | ||
dialog = AboutDialog(None, wx.ID_ANY, "") | ||
dialog.ShowModal() | ||
dialog.Destroy() | ||
|
||
def on_exit(self, event): | ||
logging.info("Tray option exit clicked. Exiting Juliana") | ||
self.RemoveIcon() | ||
wx.CallAfter(self.Destroy) | ||
self.frame.Close(force=True) | ||
|
||
|
||
class JulianaApp(wx.App): | ||
def __init__(self, *args, **kwargs): | ||
super(JulianaApp, self).__init__(*args, **kwargs) | ||
bitmap = wx.Bitmap(resource_path('resources/splash.png')) | ||
self.splash = wx.adv.SplashScreen(bitmap, wx.adv.SPLASH_CENTER_ON_SCREEN | wx.adv.SPLASH_TIMEOUT, 3500, self.frame) | ||
|
||
def OnInit(self): | ||
from juliana import APP_NAME, APP_VERSION, APP_AUTHOR, APP_SUPPORT | ||
self.frame = wx.Frame(None, title="JulianaNFC", size=(640, 480)) | ||
self.frame.SetIcon(wx.Icon(resource_path("resources/main.png"), type=wx.BITMAP_TYPE_PNG)) | ||
|
||
self.panel = wx.Panel(self.frame) | ||
|
||
self.console = wx.TextCtrl(self.panel, style=(wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_BESTWRAP)) | ||
self.console.AppendText(f"{APP_NAME} v{APP_VERSION} (By {APP_AUTHOR})\n") | ||
self.console.AppendText(f"Support: {APP_SUPPORT}\n\n") | ||
|
||
self.horizontal = wx.BoxSizer(wx.HORIZONTAL) | ||
self.horizontal.Add((8, 0), 0, wx.EXPAND, 0) | ||
self.horizontal.Add(self.console, proportion=1, flag=wx.EXPAND) | ||
self.horizontal.Add((8, 0), 0, wx.EXPAND, 0) | ||
|
||
self.vertical = wx.BoxSizer(wx.VERTICAL) | ||
self.vertical.Add((0, 8), 0, wx.EXPAND, 0) | ||
self.vertical.Add(self.horizontal, proportion=1, flag=wx.EXPAND) | ||
self.vertical.Add((0, 8), 0, wx.EXPAND, 0) | ||
|
||
self.panel.SetSizerAndFit(self.vertical) | ||
self.frame.Bind(wx.EVT_CLOSE, self.OnClose) | ||
|
||
self.SetTopWindow(self.frame) | ||
JulianaTrayIcon(self.frame) | ||
return True | ||
|
||
def OnClose(self, evt): | ||
if evt.CanVeto(): | ||
logging.info("Main window closed. Hiding to systray") | ||
self.frame.Show(False) | ||
evt.Veto() | ||
else: | ||
logging.info("Main window closed and we must stop. Exiting Juliana") | ||
wx.CallAfter(self.Destroy) | ||
evt.Skip() | ||
|
||
def OnExit(self): | ||
os.kill(os.getpid(), signal.SIGINT) | ||
time.sleep(1) | ||
os.kill(os.getpid(), signal.SIGKILL) | ||
return 0 | ||
|
||
def add_message(self, message): | ||
self.console.AppendText(f"{message}\n") |
Oops, something went wrong.