How to set up a Hunter fan Wifi control by decompiling the app

I got a hunter fan recently that was supposed to be controllable via an app called SimpleConnect. Looking at the reviews, it doesn’t work. It gets stuck on the email verification step. You get an email link that opens in the app and does nothing.

I decided to inspect the apk file with dex2jar and JD-GUI. All the confirm account step actually has to do is send a PUT request to a url with a token from the email. No need for an app at all really.

Confirming the account

To confirm the email sign up and get the email link. It should look something like

All we need is the token. The app is supposed to then make a PUT request to with a payload of

	"confirmation_token": "XXXXXXXX"

You can do this yourself in postman. Just enter the payload in the Body tab as raw JSON.


You should get a response with the same personal data you entered before. It should include approved: true.

Adding the fan

The next issue you’ll face is that the QR code is printed too small with very poor quality. The app also seems to set the camera in some sort of poor quality mode. I tried a couple devices and eventual got the code to scan with a Pixel C tablet.

Pretty amazing Ayla Networks made such a worthless app. No testing at all. But what do you expect with internet of things devices.

Google Assistant Integration

It’s not that hard to set up, but it’s not well documented. You just go here to set it up after setting up the simple connect wifi app. It’s a bit clunky saying “tell simple connect to do something” but it works.

Using Angular with a “headless” Wagtail CMS

Wagtail is a great Django-based content management system. Angular is a full-featured JavaScript framework. I wanted to use them together, so I made some helper libraries. Below, I explain how I did it.


  • Enable Wagtail features like preview and redirects.
  • Allow routing to be defined (mostly) in Wagtail
  • Maintain great performance through
    • Lazy loading JS modules
    • Compatible with Angular Universal for server side rendering
  • Ensure Wagtail Multi-site functionality works

wagtail and angular

Setting up Wagtail

Install from pypi wagtail_spa_integration using the instructions here. Since there is nothing angular specific about it – you could also use this with other front-end solutions. This package provides an extended Wagtail V2 Pages Endpoint.

Setting up Angular

Install angular-wagtail. Follow the instructions. At a high level, instead of setting routes to components, you will set Wagtail page types to either components or modules. For example the Wagtail Page “foo.MyPage” might map to MyPageComponent in Angular. I will call this dynamic routing, as opposed to Angular router’s fixed routes. This is all that’s needed for simple websites. However, angular-wagtail works by having the Angular project request page data for every page. This is a problem if your site has thousands of blog pages. Your Angular app may not need to know every blog URL up front. It just needs to know that they follow a schema like “blog/blog-post-slug”. You can make a lazy loaded module for blog and set the route like


There are some limitations. loadChildren won’t work with nested routes. If you have two components in BlogModule, then you can’t both lazy load the module and use the dynamic Wagtail driven routes. There are two workarounds. Ensure the lazy loaded modules only have one route or keep them in Angular’s routing instead of WagtailModule’s page type mapping. In the blog example, you may have a blog index page and a blog post page nested under. As long as you assume the route is always /blog and /blog/post-slug you don’t really need the dynamic routing that WagtailModule provides.

Finally you need to gather page detail data in our components. In the ngOnInit function for add something like

constructor(private wagtail: WagtailService) {}

IMyCoolPage is the interface for the data you expect to receive from wagtail for this page. This works with both fixed routes in Angular router and dynamic routes in WagtailModule.

These functions will also automatically check for redirects if a page is not found.

Closing thoughts

I really enjoy having all view logic in Angular instead of attempting to mix Django templates with a JS framework’s view layer (JSX, Angular’s templates, etc). Previously, this meant giving up a lot of features that “just work” in Wagtail. With using these packages, I can quickly bootstrap a headless Wagtail server with a separate Node/JavaScript front-end and keep all the features I’m used to. Please consider contributing some code, unit tests, or make a JS integration with your favorite framework.

Review: Pixel Slate for Linux and Web Development

The Pixel Slate (i7 model) can be a decent computer for web development, including Docker, Node, and Android development. My workplace recently got me one so I decided to review it for anyone curious about using it for Linux-based development.


I’m reviewing the highest-end version with an i7-8500Y CPU. Let’s break that down:

  • Y series is the 5 watt low power offering (not to be confused with the 15 watt U series which is for “Ultrabooks”).  This allows the Slate to not have any vents or fans, making it perfectly quiet.
  • The 8 stands for 8th generation which is the newest generation for the Y series.
  • The “i7” means it’s both more expensive and faster than the same class i5. But that doesn’t mean an i7 Y series is going to be faster than a very old i3 desktop K series CPU. It’s essentially the same chip with more cores enabled and a higher clock frequency.

The i7-8500Y is considerably slower than a roughly equivalent i7-8550U as seen in the XPS 13 9370. (See my review of the XPS 13 developer edition here). Since I have both, I’ll do a few comparisons. All tests on the XPS 13 are run on Ubuntu 18.10.

Basemark Web 3.0
Pixel Slate – 500.4
XPS 13 – 365.8

Wow – the Slate beats the XPS here – this is surprising! Both are running Chrome. My guess is that Chrome on the Slate has far better optimized drivers than stock Ubuntu on the XPS. This probably allowed the GPU to do more of the work, resulting in a higher score.


I tested building Passit, the open source password manager I’m working on. Passit is built with angular-cli and uses webpack to build bundles. See the repo here if you want to compare. I ran a development build with “npm run build”

Pixel Slate – 16 seconds
XPS 13 – 11 seconds

CPU benchmark

I ran “sysbench –test=cpu –cpu-max-prime=20000 –num-threads=8 run”

Pixel Slate – 5.8 seconds
XPS 13 – 10.0 seconds

Lower is better – and the Slate wins. I don’t understand this. It should be a simple CPU test, and the XPS 13 has a faster CPU with more cores. Since this test had odd results, I ran “stress-ng –cpu 6 –cpu-method matrixprod –metrics-brief –perf -t 60” too.

6 cores:
Pixel Slate: 22839 ops
XPS 13: 46106 ops

2 cores:
Pixel Slate: 25464 ops
XPS 13: 33069 ops

This time the XPS got more than twice as many operations done in the 6 core test – presumably due to its extra cores. Even with just 2 cores, the XPS is still faster.

Docker and Django

As an example of back-end development, I’ll run the passit-backend (Django) tests in Docker. This shows the time required for creating a PostgreSQL database and running the Python tests. I ran:

– docker-compose up db
– time docker-compose run –rm web ./ test

Pixel Slate – 38 seconds
XPS 13 – 26 seconds

This test involves a mix of CPU and I/O bound operations. It’s not surprising that the XPS wins.

Linux Apps

Screenshot 2018-12-23 at 16.54.29
Just a typical day in Chrome OS running Firefox, VS Code, and Docker

I installed Firefox within five minutes of opening the Pixel Slate – because why not? Linux apps run mostly well on the Slate. Setting them up is easy – just enable that option in settings. Installing apps is easy for someone experienced with the Linux command line, but harder for someone new to Linux. For example, on most Linux OS’s, you can double click a package file (such as a .deb file) and it installs. Not so on Chrome OS – you’ll need to use apt and dpkg to install programs like VS Code and Firefox.

Linux in Chrome OS (called Crostini) runs Debian Stretch in a container-based environment. That means it’s more efficient than a virtual machine and more secure that just executing Linux programs directly. It does add some inconveniences, such as having a separate file storage area (similar to Android).

Most things work just fine, but an exception was Docker. I followed the comments here to get it working. I ran into another minor kink when installing gnome-terminal because no shortcut was created (every other app I installed did so and “just worked”). Crostini doesn’t support GPU acceleration at this time, so Steam gaming with the Slate isn’t going to be a great experience. Actual virtualization doesn’t work at all, although Wine does.

One perk of using the Slate as a developer is that you can develop Android apps and run them right on the device without an emulator. This does require enabling developer mode, which leads you to a rather annoying startup screen that must be bypassed by pressing CTRL-D or waiting 10 seconds. It’s actually really handy running Android apps directly in Chrome OS and not taking the typical performance hit from full virtualization.

Mobility, Battery Life, and Other Features

The Slate weighs 1.6 lbs by itself; with the keyboard it’s 2.9 lbs. For comparison, the XPS 13 weighs 2.67 lbs – so the Slate as a laptop substitute is not a lighter option.

I get 4-6 hours of battery life on the XPS 13 when actually working. The Pixel Slate does better – more like 6-12 hours. (It’s hard to estimate because I’m typically not continuously coding/compiling things for more than 6 hours at a stretch.) This is no surprise given the lower power requirements of the Slate’s CPU.

The Slate easily goes into a suspend mode when inactive, just like an Android phone or tablet would. Ubuntu on the XPS is more finicky – it mostly works, but consumes more power when suspended and occasionally has glitches when waking. I would feel comfortable simply suspending the Slate when I step away from my work, whereas I often shut down my XPS 13 to avoid the issues just mentioned.

The Slate doesn’t have a headphone jack, and only has two USB-C ports. If I want to charge it, listen to music (through an adapter), and plug in a second monitor at the same time, then I need a USB-C dock. Google doesn’t provide much guidance on what adapters or docks are supported. I found USB-C to DisplayPort to work fine with a 4k monitor at 60hz, while a USB-HDMI adapter I use for my XPS didn’t work at all with the Slate. USB-C docks don’t support 4k at 60hz, and the ports appear not to be Thunderbolt-compatible. I found this whole connection process confusing and annoying – but in the end I got what I wanted using a USB-C dock (for power and audio) and a separate cable for DisplayPort.

The official Slate keyboard works as well as any device in this tablet-to-computer product class. It’s usable on your lap, but not good. It’s perfectly fine on a table. The round keys are a little odd, but I got used to them. It’s almost a full keyboard, including escape and F row keys – meaning I can use vim with it.

This may be a matter of personal taste, but I find the Slate too large and burdensome for reading an e-book. One advantage of the size, though, is that I can read full-size magazine articles without having to zoom or use the lite version.

The Slate’s magnets seem to be weaker than the Pixel-C’s, or maybe they’re the same but not strong enough for the increased weight. The Slate wouldn’t stay up when I tried sticking it to the fridge like I do with my Pixel-C. At the Slate’s vastly elevated price point, however, I probably wouldn’t trust it in the kitchen anyway!


As a developer, I’d feel confident using the Pixel Slate as a replacement for my tablet and laptop. I’d still want a faster desktop with this set up and as a backup just in case Docker or something didn’t work right. As something I got from work and didn’t pay for myself – it’s great!


  • Great battery life
  • Fast web performance
  • A good way to run Linux with a solid, stable base OS that runs without glitches
  • Running Android apps next to Linux apps all inside Chrome OS is really cool


  • Expensive – I could buy both an XPS 13 and a small tablet for less money
  • CPU performance is slower than an “ultrabook”
  • No headphone jack and not enough USB-C ports

rxjs check as your type validation

rxjs has a steep learning curve, but can do some really cool things. Let’s say you want an input form to do “as you type” async validation. Perhaps it’s checking if the username is taken or not. Another use case could be checking if some url is valid. I implemented this with ngrx-effects (after failing a lot!) and thought I would share.

  asyncServerUrlCheck$ =
    filter(form => form.value.showUrl),
      (first, second) => first.value.url === second.value.url
    switchMap(form =>
            () => new StartAsyncValidationAction(, "exists")
          map(() => new ClearAsyncErrorAction(, "exists")),
          catchError(() => [
            new SetAsyncErrorAction(

Lots going on here and it sums up both my love and hate of rxjs. It’s unreadable garbage code until you understand it – then it’s fantastic. Let’s try to break this mess down.

First off – notice the asyncServerUrlCheck observable (All ngrx effects are just observables) is watching state instead of actions$. This is done because I’m watching the form field’s state instead of waiting for an action. Then I filter out changes that are not to the form field in question and I make sure it’s a real change.

Now the magic starts – next in my pipe is switchMap which is important because I want to cancel any previous observable.  If the user types and then I probably don’t want to check if exists. switchMap throws out any previous work and start over. Of note – if I didn’t use switchMap I would see a LOT more network requests.

Next up is concat. concat is what is going to allow me to return multiple actions. Without it, I would just get the first start async validation and nothing else. concat is a static function and not a operator (Oh but it was an operator in rxjs 5 – which actually makes me hate rxjs a little because it’s so much mental overhead!). We’ll pass observables as parameters to concat. Our first concat observable is a timer. Timer is what implements the logic to wait until the user stops typing. Because we use it with switchMap earlier – it will get canceled if the user types something else! We could stop right now and have a start async validation action dispatch when the user stops typing. Cool. I do suggest trying this out piece by piece if you want to understand it rather than coping the entire snippet.

Now I need to add success and failure actions after the async call is made. I’ll add a second parameter to concat which is my service function call. The function will return an Observable (Once again remember that concat accepts a list of observables). I pipe this into a map and catchError. That logic should look familiar if you used effects before so I won’t go into detail.

Screenshot from 2018-07-11 10-01-35

This is how it looks in redux devtools. I get lots of set value’s from each user character input. But I don’t get a start async validation for each one (meaning I don’t excessively check the server!). Then I get either set async error or clear async error (success) actions depending on if the server url is valid.

I’ve found this pattern hard to grok initially – but now is easy to apply elsewhere. Making async validation easy means I’ll be more likely to use it and give users a more interactive experience. Try it yourself at and download the chrome or firefox extension (The web version ask for server url). And if you aren’t a regular visitor to my blog – Passit is an open source, online password manager that my company built so please give it a try.

Forms with ngrx, NativeScript, and Angular

There are many ways to make forms in Angular. There’s template driven, reactive, and the question of syncing with ngrx state or keeping the it local to the component. When making a NativeScript app it’s not always obvious how to reuse these forms. For example, template driven forms in Angular might use the dom’s “required” attribute.  NativeScript doesn’t have a dom or input component at all, so the required logic would have to be remade, perhaps using a required directive. Redux/ngrx driven forms offer a significant advantage when we have multiple platforms as ngrx is platform agnostic and we can perform the validation logic in the reducer instead of the component or a directive.

As a case study, I recently rewrote Passit’s login form with the fantastic ngrx-forms package. ngrx-forms takes care of common use cases while providing a blueprint and examples of how to make the state driven forms.

The validation logic is in the reducer, here two different platforms show the errors that get pulled from state

Using ngrx-forms on the web is straight-forward, just follow the docs. For NativeScript you’ll have to make a few changes:

  • There is no “form” component in NativeScript, so you’ll have to manage isSubmitted yourself. You could modify the submit state in the reducer itself or in the component with MarkAsSubmittedAction.
  • ngrx-forms comes with directives to keep the form and ngrx data in sync. But these won’t work out of the box with NativeScript components. Here is a NgrxTextFieldViewAdapter for a TextInput. Just add the directive like [ngrxFormControlState]=”form.controls.yourField” and the TextInput state will sync with the form state, just like on the web.

Now I can reuse all of my form validation logic in both platforms. The only difference is the presentational components for app and web.

Overall I think ngrx-forms offers a straight forward, redux friendly, and platform agnostic solution to forms. Please feel free to take a look at my Android preview release of Passit, the open source password manager. As I create more forms on both platforms I’m looking forward to having a single strategy for building them. Be sure to report bugs on gitlab.

Does your password manager really need permissions to do anything ever?

Screenshot from 2018-03-03 12-01-59

Almost all password manager’s browser extensions have permission to “Read and change all your data on the websites you visit”. If that sounds scary, it’s because it is. That’s the “<all_urls>” permission. It means the extension is allowed to execute arbitrary JavaScript at any time on any website without warning. Here’s some examples of what I could do if you installed an extension I made with <all_urls>.

  • Run a keylogger on every webpage you visit
  • Inject extra ads into every website
  • Run a password manager that autofills every login form even when you do not ask it to – this is in fact common. This includes malicious forms that might have been injected into a victims website to steal your password.
  • Run a password manager that checks each and every domain you ever visit and forget to sanitize the domain url making it vulnerable to code injection attacks that could lead to a rouge website capturing all of your passwords.
  • If I’m feeling only slightly evil, I simply record each domain you ever visit and sell that data to advertisers.

Passit does not require the <all_urls> permission. This doesn’t make us invulnerable to all extension-based attacks, but it greatly mitigates them. Let’s consider some:

  • “I sell you out (perhaps to another company) and start making my extension serve ads or other garbage” – you’d get a notification about the increased permissions and hopefully you’d check our blog to see why we want scary permissions.
  • “My sloppy code is vulnerable to JS injection attacks” – but because Passit doesn’t run until you invoke it, that probably only happens on websites you already know and trust at least somewhat.

Forget security vs convenience

(Sort of)

Passit has easy to use shortcuts for autofill, so you don’t give up much convenience. I personally don’t find pressing a shortcut key to log in to be a big burden, especially with such nice security gains. Our strategy also means Passit will never have Clippy-esque “Would you like to save this password??” forms because Passit will never bother you until you activate it.

That said, Passit is positioned to be a web-based, easy-to-sync, and share/organization-friendly password manager. I think password managers like pass still offer a benefit for personal use when you don’t care about sharing or autofill. The most secure password manager would be a piece of paper in a safe in a fort. At some point, we have to pick where we are comfortable between security and privacy vs convenience. I hope Passit makes an appealing choice that is nicer to use than programs like pass or KeePass while providing better security and privacy than LastPass or 1Password.

Try Passit out today. Use our free hosted service or run it yourself. If you like it, please star us on Gitlab and report some feature requests or issues.

Review: Dell XPS 13 9370 Developer Edition

As the owner of Burke Software and Consulting I get to play with a few more Linux laptops than I would as an individual. I recently picked up Dell’s latest XPS 13 (9370) Developer Edition. Here’s my review as a developer.

Comparing Laptops

I compared the current 9370 model with the 2016 9350 model. I also compared a couple benchmarks with the Galago Pro 2 from System76, which is another laptop with Linux preloaded.

Both XPS computers are top of the line with Intel i7 branded CPUs. The 9370 is an 8th generation Intel i7-8550U CPU while the 9350 is a 6th generation i7-6560U. The Galago Pro was configured with a i5 processor – so while it’s interesting to throw in it’s not a totally fair comparison.

Hardware and Appearance

The 9370 model is noticeably slimmer as seen in these photos. The other dimensions are the same. It’s noticeably a little lighter too. I tested it with a friend, having them close their eyes and pick the lighter laptop to make sure it wasn’t a placebo effect. The Dell USB-C charger is also a little bit smaller which is nice.

The camera is still unusable due to its placement. Dell moved it to the center in the 9370 model which is maybe a slight improvement, but all you will see is your fingers on the keyboard and up your nose with this camera. I can’t think of any circumstance in which I would use this horribly placed camera.


I benchmarked some typical developer tasks. I tested by building the open source password manager Passit. This has been my passion project for the past couple of years and if you aren’t using a password manager yet and like open source I encourage you to try it out (and give me feedback).

I tested a Webpack bundle from the passit-frontend Gitlab repo. This runs angular-cli’s serve command.

yarn start (webpack)
9370: 11173ms
9350: 12322ms
Galago: 13945ms

It appears the 9370 is only slightly faster, saving about 1 full second. That is not impressive for a upgrade of two CPU generations.

Ubuntu Disk Utility Benchmark
Average Read Rate
9370: 2.7 GB/s
9350: 1.6 GB/s
Average Access Time (lower is better)
9370: 0.04 msec
9350: 0.22 msec

Looks like the 9370 has a faster SSD. That’s always a good thing. We can see how benchmarks look impressive but real world results don’t reflect it.

time tns run android
9370: 1m 49s
9350: 2 m9s

This test uses the passit-mobile repo. There’s a lot going on. It needs to compile the typescript into JavaScript, build the apk file, start an android emulator, and load the apk file on the device. I did my test using the Unix “time” command. I manually stopped it when I saw the Passit app fully loaded in the emulator. I like this test because it does SO much. Some of the Android compilers take advantage of multiple cores while the node based tools can use only one core. A big change on the  i7-8550U CPU is having 4 cores and 8 threads (previous comparable U series CPUs had 2 cores). We can see a decent speed boost on the new XPS here. Nothing ground shattering. If your workload is more multi core utilizing you might see bigger jumps in performance.

All tests were done on battery.


I was pleased to see a good boost in battery life on the new XPS 9370 despite it having smaller battery and a higher resolution display of 3840 x 2160 (9350 topped out at 3200 x 1800). Battery testing is hard and your results will vary. In the type of work I do (web development, vim, browsing) I got about 4-5 hours on the 9350. I seem to get around 7-8 on the 9370. I’ve only been using it a couple days, so I’ll update this post if I find it varies. On both set ups I do not have powertop or TLP installed – I find they can make Linux too unstable for me.

If you opt for the lower screen resolution on any XPS model, you will get vastly better battery life. Unfortunately, Dell does not offer the lower resolution with 16GB of RAM, which made it not an option for me.


The XPS 13 line is not for gaming so I’ll keep this short. The 9350 had an Intel Iris integrated GPU option while the 9370 offers only the less powerful UHD 620 integrated GPU. At first I was worried this would mean no more Cities Skylines for me – but that is not the case. Cities Skylines runs just fine on very low settings on the 9370. Dell says the heat dissipation is improved on their new laptop so it may be one reason for decent performance even without the better Iris GPU. If you want some light gaming, the XPS 13 dev edition is a solid choice.


The new Dell XPS developer edition is a modest improvement. I think the better battery life even on the higher end model is the biggest improvement. It’s probably not worth upgrading from the 9350 model but it might be from anything earlier. Performance gains are minimal, possibly due to Intel CPU’s having only minor performance upgrades the past couple years.