Making Stickers

Sticker paper is easy to find, but without post-processing the stickers aren very durable. A bit of moisture and the ink starts to run. Let test if a few coats of varnish can make them more resistant. If you aren blessed with good penmanship, printing stickers is an easy out to get good-looking labels without hours of practising calligraphy. However, my first few stickers for spice jars and deck boxes had two main issues; the ink would run very easily when getting a little moist (pretty bad for items in the kitchen). Also, the colors weren quite as vibrant as I would have liked. While there are plenty of options to be found on the internet to make better stickers, some including a lamination machine, the easiest seemed to apply a few coats of varnish. So let have a look if this has an effect! Materials needed A printer Sticker paper suitable for your printer (InkJet or Laser) Varnish (Rattle Can) A cutting mat, X-Acto knife, ruler Printing the stickers This will depend on the type of printer you have, and the paper used, so experiment a little to find the best settings. For me that turned out to be Read more…

Web Bluetooth Notifications Sample

The Web Bluetooth API lets websites discover and communicate with devices over the Bluetooth 4 wireless standard using the Generic Attribute Profile (GATT). It is currently partially implemented in Android M, Chrome OS, Mac, and Windows 10. This sample illustrates the use of the Web Bluetooth API to start and stop characteristic notifications from a nearby Bluetooth Low Energy Device. You may want to try this demo with the BLE Peripheral Simulator App from the Google Play Store and check out the Notifications (Async Await) sample. var myCharacteristic; function onStartButtonClick() { let serviceUuid = document.querySelector(‘#service’).value; if (serviceUuid.startsWith(‘0x’)) { serviceUuid = parseInt(serviceUuid); } let characteristicUuid = document.querySelector(‘#characteristic’).value; if (characteristicUuid.startsWith(‘0x’)) { characteristicUuid = parseInt(characteristicUuid); } log(‘Requesting Bluetooth Device…’); navigator.bluetooth.requestDevice({filters: [{services: [serviceUuid]}]}) .then(device => { log(‘Connecting to GATT Server…’); return device.gatt.connect(); }) .then(server => { log(‘Getting Service…’); return server.getPrimaryService(serviceUuid); }) .then(service => { log(‘Getting Characteristic…’); return service.getCharacteristic(characteristicUuid); }) .then(characteristic => { myCharacteristic = characteristic; return myCharacteristic.startNotifications().then(_ => { log(‘> Notifications started’); myCharacteristic.addEventListener(‘characteristicvaluechanged’, handleNotifications); }); }) .catch(error => { log(‘Argh! ‘ + error); }); } function onStopButtonClick() { if (myCharacteristic) { myCharacteristic.stopNotifications() .then(_ => { log(‘> Notifications stopped’); myCharacteristic.removeEventListener(‘characteristicvaluechanged’, handleNotifications); }) .catch(error => { log(‘Argh! ‘ + error); }); } } function handleNotifications(event) { Read more…

DeckLock part 2: Magic the Gathering

DeckLock, a static-website generator to generate overviews of KeyForge decks, will be expanded to support Magic: the Gathering. To find more about DeckLock and how it is designed look at the previous post. Magic: the Gathering is a very different game compared to KeyForge. There is a large pool of cards available and players can select a set they wish to play with. There are different formats and the format determines which cards and how many of them you can play. Most formats require decks to be at least 60 cards with any number of basic lands and a maximum 4 copies of other cards. This means each player can bring a completely custom set of cards to the table and we’ll have to come up with a system to support that. Unlike KeyForge where each deck is unique and the list of cards can be found online, here we’ll include a system to add a deck list, with a short description and turn those into pages containing cards. You can find my DeckLock instance with an overview of my KeyForge and Magic: the Gathering decks (paper and online) here. Designing a Reader Here we actually can use a structure Read more…

Learnings from analysing my compromised server

Returning back home. I get this buzz on my phone. Turns out it’s an email from Linode. Daym. I thought was I billed already? Trust me on this, I was really not sure what to do of this for the first two minutes when I read the email. I opened the Linode admin panel to check out what was my server up to. And the CPU graph had jumped off the hooks. Same was the case with the network graph Looking at the network log’s suggested a high amount of outbound traffic coming from my server, further cementing the Linode support ticket that I got. I ssh’d inside my server to see what was going on. I will be damned. I don’t remember sleep typing my password continuously for that long! Let me tell you, you don’t do a cat /var/log/secure at this point as the file would just be spit continously at you with no end of stopping. Did head (even a tail can do) to it. Going through the start of the file, everything was fine until I started to see the extremely less epoch time between two failed attempts. This confirmed my hunch that some script kiddie was trying to brute force through Read more…

Getting a script’s path in R

Recently I found myself using R scripts from others and having to deploy my own R code on other machines. The majority of these had a hard coded path to either the script or the input data somewhere in the code. This becomes an issue when code needs to run on different machines, so here is a quick solution to this issue. While I prefer Python over R, I do need to use R from time to time as some packages have no equivalent in Python (yet). One issue with R I seem to be running into quite often is that depending on how you run a script, the working directory may or may not be set to that script鈥檚 directory. Especially those that like to open their .R files in RStudio without creating a proper project (like me) are likely to run into issues where the working directory isn鈥檛 necessarily the folder the script is in. A quick-and-dirty solution is to use setwd() to set the working directory in the beginning of the script to your local folder. However, if that script needs to be run by someone else on their machine, that path needs to be changed. The Read more…

Adding Aqara Sensors to Home Assistant

Home Assistant is running great! It is time to add some more devices to my setup, and since all groundwork to add Zigbee devices using Zigbee2MQTT was done previously (check out this post) it makes sense to add more devices that support this protocol. For this post I picked up two Aqara sensors which can measure temperature, humidity and air pressure in a small form factor. Pairing new Zigbee devices First we need to pair Zigbee2MQTT to the new sensors, to do this we’ll have to log onto the Raspberry Pi and edit the file /opt/zigbee2mqtt/data/configuration.yaml. Find the line that says permit_join: false and change this to permit_join: true. Then restart Zigbee2MQTT using the commands below. sudo nano /opt/zigbee2mqtt/data/configuration.yaml sudo systemctl restart zigbee2mqtt Now Zigbee2MQTT is ready to pair with new devices. To pair a sensor, press the button on top. Once you press the button it will blink once indicating it is pairing and upon connecting it will blink twice. Now go back into /opt/zigbee2mqtt/data/configuration.yaml and give your device a name, this is done by adding a friendly_name tag to the device as shown below in my configuration file. … devices: ‘0x00158d0003495e50’: friendly_name: Aqara Cube ‘0x00158d00068b6c2e’: friendly_name: TMP Sensor Read more…

How to Upgrade Your Nintendo 3DS with USB-C Charging

Are you tired of fumbling with your Nintendo 3DS charging cable? Do you wish you could use a modern, reversible USB Type-C connector instead? With a few common tools and a little know-how, you can add a USB Type-C port to your Nintendo 3DS charging cradle in no time! In this blog post, we’ll show you how to modify your charging cradle to accept a USB Type-C connector, so you can charge your device with ease. We’ll cover everything from the materials you’ll need to the step-by-step process of drilling and soldering. This process is similar to adding a USB-C port to a Raspberry Pi Pico, which we covered in a previous post. The Nintendo 3DS charging cradle is a good candidate for this modification as there is plenty of room on the inside to add a USB-C breakout board and wire it up to the charging PCB. What you need Before we begin, let’s make sure you have all the tools and components required for this soldering project. Here’s what you should have at your workspace: A 3DS charging cradle Electrical wire – You’ll need two pieces (preferably black and red), which can be repurposed from e.g. an old Read more…

Setting up a Google Cloud Function

With Google’s Cloud Functions you can make simple microservices that can perform a task on Google’s infrastructure. This allows some functionality of an app to be moved to the cloud. This can be useful in a number of cases; for instance the Dashboard from a previous post. When running scripts on a platform like the Kindle Paperwhite, you are somewhat limited to which tools and packages you can use easily. For instance installing additional python packages would be a non-trivial step, as is installing other software. Therefore, the script makes use of vanilla regular expressions to parse html instead of a more specialized package like BeautifulSoup. However, when more complex processing is required, re-implementing everything would be quite cumbersome. So here a cloud function could be a great solution. Each function can be called through an HTTP request, similarly as most web APIs. The script will then be run on Google’s hardware and the results are passed back in a response. As an example I’ll set up a Cloud Function that will grab citation data from a Google Scholar profile, as Scholar has no API, the only way to get citation statistics is to parse them out of the HTML Read more…

An Agent Based Model to look at Gwent Pro Ladder (results)

With the Agent Based Model (ABM) from the previous post we can simulate any number of Gwent players, with known skill and play rate, playing throughout a season. Using this model we’ll try to get a firmer grasp on the ladder system and test whether this rewards skill or grinding games… Climbing Pro Ladder Skill vs Grind The ABM mimics a population of agents playing Gwent for an entire season with different innate skill and time to play. Though unlike with actual people we can change the parameters of the model to examine what we want to test. So in the first model we’ll disable any kind of learning, where agents would get better as they play more games, to see only the impact of playing more games on the peak MMR score (of a single faction). To do this a model was run with these parameters: 8000 players 100 steps resulting in players playing 25-170 games per season no learning players don’t get better by playing more games initial skill ranges from 1200-2700 distributed similarly as chess players After running the model with these parameters, we can group players by skill (in bins of 200 ELO) and amount of Read more…

Plotting post hoc tests with Python

When three or more groups of samples are compared (e.g. Using ANOVA/Tukey HSD or Kruskal-Wallis/Dunn), you often see results shown as a boxplot, with lines highlighting which groups are significantly different. In Python there is no single package to do this quickly, though by combining scikit-posthocs with statannotations similar plots can be generated with relative ease. Here wego over the code involved step by step. Statistical tests comparing three or more groups are typically done in two steps. The first test will check if there are any statistical difference between the groups, the second test will then tell you which groups are different. The second test is referred to as a post hoc test. While there are many combinations of tests to choose from, common combinations are Kruskal-Wallis followed by a post hoc Dunn test (non-parametric) and ANOVA with Tukey Honest Significant Differences (parametric). Though note that the code below can easily be adapted for other tests. All code from this post can be found on GitHub and Binder. The data The iris dataset, with measurements of petal and sepals of three species of flowers will be a nice way to test some of these test. The code below will Read more…