Preface: This was originally drafted in September 2020, and is only being published ~2 years later. I can’t remember my exact mood when I drafted this article, but apparently it was one of those days. It was also not the first time I’d experienced this issue. I hope posting it here will allow me to not experience this issue again, and help someone else who befalls a similar misfortune.
I hate everything. That’s right. Everything! ARGH! Cue continuos shouts into the void.
Issue: Laptop won’t output audio over HDMI. There is no setting anywhere that seems to allow you to output to HDMI, even though you could swear you’ve done it before. Also every ‘solution’ on the internet tells you to do something you’ve already done or change a setting that doesn’t exist.
Device: Asus FX502VM, Windows 10, GeForce GTX 1060
Early in the pandemic my employer had us working from home. For the most part this was not an issue. But not having a dedicated office, I found it too easy to lose track of time, and spend too much (in my opinion) time working. With my computer set up in our lounge, it was too easy to check an email, or quickly test something else. It was right there.
There was also no separation that came from cycling/taking the train to or from work. Wake up in the morning, sit down at the desk with breakfast/coffee, start working. Without planned events in the evening, continuing to work was easy.
I have not worked enough (4+ hours). First LED is a status.
In an effort to limit this I once again repurposed my Particle Internet Button to do some time tracking. I’d used Toggl in the past to do some time tracking, but liked the idea of having a visual display available to me, without having to pull out my phone, or install additional applications on my work laptop.
My basic idea was to use the Particle Internet Button as a switch and display mechanism for interfacing with the Toggl API. The main issue I encountered with this approach was that Toggl was enforcing https for their API calls (and rightly so), but there were complications around the available Particle https libraries at the time.
I have worked too much (9+ hours)
Not wanting to spend the time on figuring that out, I somehow convinced myself that I should just spin up my own “Toggl-like” service. Obviously just for me, and not requiring https :) Hopefully my employer doesn’t hack my Wi-Fi to intercept my network comms and make me think I’m working less than I actually am.
And so that’s what I did. I setup a database, and threw together some php scripts to interpret different requests as start and stop commands, also taking a date-time string as a parameter. I expanded it a bit, allowing for different work-id’s, if I want to track different topics, and protected it all behind a nice long ‘key’ to limit the risk of someone messing with my data.
I have worked an appropriate length of times (8+ hours)
The Internet Button itself is round, and has a bunch of RGB LEDs on it. Eleven LEDs lets me use one for a notification, one as a spacer, and the other nine as hours worked increments. The Internet Button does have buttons that can be used as inputs, but instead I chose to use the accelerometer to give me a more intuitive input, without the need for labels.
My beautiful web interface
I 3D printed an octagon-shaped holder for it, which allows me to rotate the internet button to five fixed locations, which are easily distinguished from each other by the accelerometer. If you’re in the central position, the timer stops. If you shift to one of the other four positions, you start the timer associated with that position. In practice I’m only using one, so the other’s are mostly untested for now.
If I don’t have the hardware with me at any time, there’s also a basic web-interface, that allows me to view the entire week’s hours worked, and each stop and start event. I can also add events if I forgot to start or stop at some time.
Page title includes hours worked, and auto-refreshes every 5 minutes
Here you can find a link to a GitHub repo with some associated code: link
Below you can see a video of it working, and interspersed in this article are a couple photos of different stages.
I’ve been working on a minor python project recently, and went back to my old friend TkInter. TkInter is the standard GUI library for Python. I had used it previously in another small project, so when I wanted to quickly get a GUI going for a project, it made sense to use TkInter. There are many other GUI libraries, but TkInter is supposedly one of the quicker and easier to get going.
TkInter has a number of shortcomings. It’s clunky and not completely intuitive. But the biggest issues that I experience with it is trying to get the interface to update from an outside perspective. My specific implementation required me to update about 20 values on the GUI by reading data from a serial port.
The easiest way to implement this is to make use of the TkInter Label widget. The Label is used for displaying any kind of text. A label can be linked to a TkInter variable, so that if you update the variable, the label automatically gets updated. The difficulty is that you need an event to trigger an update of the variables.
The way to get around this is threads. Python has built in support for threads, via the Threading class. And so you create a thread, and pass it the Tk variables and update them from the thread. This allows you to continue doing other things in the GUI, and still have your thread run. Or does it.
The immediate issue is with how TkInter queues up tasks. Because the label uses Tk variables, you can only update them by calling a set method. Not just by declaring the variable equal to a value. As such this set gets added to a queue. I found that when I clicked a drop down menu (Tk.OptionMenu), my updates would pause. My thread would effectively pause as it waited to be allowed to call the variable set method.
This was not the end of the world, and I probably would have left it like this if I didn’t continue to have the program crash unexpectedly. It would happen often, but at different times, and only when I was interacting with another aspect of the GUI. For example, when I clicked a button or selected a menu item. The program would freeze, causing the python itself to crash, and not reporting any error.
I battled to find much info on this topic. All I’ve been able to come across is the repeating statement that “TkInter is not thread safe” and that you shouldn’t try to access TkInter widgets, except from within the main thread.
There are a couple ways around this. What I ended up using is the TkInter after method. It’s janky. But it works, and has proven reliable. Since I made the change, I have not had my app crashing any more. Now I have a global variable to store the data from serial in. I have a function within my GUI object that updates the Tk variables from the global array. It then calls itself using the after method.
The after method adds a note to TK to do something after a specific amount of time has lapsed, and appears to operate much like an interrupt, ignoring whatever else I am doing and updating on schedule. I first came across the after method as described by Furas on StackOverflow.
Below is a summary of what I was doing before, and what I am doing now.
Before:
class SerialThread(threading.Thread):
def __init__(self, gui_object):
threading.Thread.__init__(self)
self.gui = gui_object
def run(self):
#Read serial info
self.gui.variable1.set(SERIALDATA)
class GUI():
def __init__(self):
self.root = tk.Tk()
self.variable1 = tk.StringVariable(self.root)
label1 = tk.Label(self.root, textvariable=self.variable1)
label1.grid(row=1,column=1)
thread1 = SerialThread(self)
thread1.start()
self.root.mainloop()
if __name__ == "__main__":
GUI();
And after:
TempVariable = "XXXX"
class SerialThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global TempVariable
#Read serial info
TempVariable = SERIALDATA
class GUI():
def __init__(self):
self.root = tk.Tk()
self.variable1 = tk.StringVariable(self.root)
label1 = tk.Label(self.root, textvariable=self.variable1)
label1.grid(row=1,column=1)
self.updateLabels()
thread1 = SerialThread()
thread1.start()
self.root.mainloop()
def updateLabels(self):
global TempVariable
self.variable1.set(TempVariable)
self.root.after(10,self.updateLabels)
if __name__ == "__main__":
GUI();
UPDATE – below code skips the global variable and uses a thread lock:
class SerialThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.serial_data_to_display = ""
self.lock = threading.Lock()
def run(self):
while True:
with self.lock:
# serial read stuff
self.serial_data_to_display = "SERIAL DATA"
sleep(0.1)
class GUI():
def __init__(self):
self.root = tk.Tk()
self.variable1 = tk.StringVariable(self.root)
label1 = tk.Label(self.root, textvariable=self.variable1)
label1.grid(row=1,column=1)
self.thread1 = SerialThread()
self.thread1.start()
self.root.mainloop()
self.updateLabels()
def updateLabels(self):
with self.thread1.lock:
self.variable1.set(self.thread1.serial_data_to_display)
self.root.after(10,self.updateLabels)
if __name__ == "__main__":
GUI()
I’ve recently gone through the process of moving one of my domains from one domain registrant to another. For a couple reasons, but cost and whois privacy are part of it. I’ve switched hosting providers a number of times, and that’s not an issue, but getting different domain registrants on the same page to ensure a downtime-free transfer isn’t a clear process to me, so during this time I was particularly susceptible to notifications about the transfer.
It was then that I noticed an item in my spam account titled “Domain Expiration SEO”. Now I didn’t notice the SEO in that title at first, and was immediately concerned about the terms “Domain Expiration”. The fact that it was in my spam folder at least made me immediately cautious, but the fact that they used my full name and postal address in the “invoice” confused me.
The email had a large title saying “Final Notice, your account is pending cancellation”, th email came from “info@antera.org”, a domain with no discernable website, and links on the page directed to “domaschooner.win”. What I don’t like is that the entire premise is that you’re about to let something that you had expire. In the meantime nothing could be further from the truth.
It seems they somehow identify domains that are being transferred, grab the whois data and then generate emails, in my opinion, hoping to catch people not paying attention into paying $86 for supposed SEO software.
If you pay close attention to the email, they do note that they “…do not register or renew domain names…” and their email disclaimer states “…This is not a bill or an invoice. This is a SEO purchase offer. You are under no obligation to pay the amount stated unless you accept this purchase offer…”. So while they do a good job of telling the truth, the immediate implication of the email implies something worse. So while probably not illegal, very shady.