Blog


P38 part 1 – adding android

I’ve had limited success doing multi-part posts in the past, but for this little ongoing project I thought I’d give it another go….

At the ripe old age of 38, in April 2018 I passed my driving test (4 minors, all to do with use of mirrors!) and decided to buy my first car. Rather than go for something boring, that just…worked, I thought I’d go for possibly the most troublesome, unreliable and badly engineered car I could find which led to me spending in the region of £2000 on this beautiful boxy vision of british engineering:

A 2001 Range-Rover (P38A) with a 4.6L V8, converted to run on LPG (so I can actually afford to drive it).

This series of posts will (until I get bored) detail my attempts to combine my love of technology with my love hate relationship with this car.

My first job (after fixing up a couple of minor issues with a wing mirror and the bodywork) was the main centre console. Being a 2001 model, my car came with a state of the art (17 years ago) satellite navigation system, which looked something like this:

Sexy right?

I decided to go with an android unit, of which there are literally hundreds available, however in what was soon to become a recurring theme the P38 added an additional problem. Well, 2 really. First, the space the sat nav fits into isn’t quite a standard ‘2 DIN’ slot. It’s about 5mm too small. Why? only Land Rover could tell you. And secondly, the slot is also not deep enough for the majority of car head units. There’s about 4 inches of clearance behind the screen.

Luckily, a bit of digging around on some very useful forums (http://landyzone.com mainly) led me to this on ebay. It’s standard 2 DIN but (significantly) it’s much shallower than other units, only needing a couple of inches of clearance at the back.

And so, one weekend, this happened:

Seats came out for a different project (I bought new seats) but they also gave me a lot more access to where I needed to get to.

Bonus action shot. You can see the tangled rats nest of wiring here, lots of fun figuring out what goes where. Luckily for my head unit I only needed to locate a battery 12v, a ground and an ignition switched 12v.

For the audio I decided to leave the original stereo in place since the subwoofer in the boot was actually still working (the amp for this is a common source of failure on these cars, so I was pleasantly surprised by this). To connect a standard audio signal into the original stereo head unit, you need one of these Grom audio cable which converts the CD changer connector to an auxilary line in.

To fix the ‘Not quite the right size’ problem I used a dremel and cut away part of the bottom edge of the hole, then hot glued the unit into position. No pictures of this process unfortunately, because I’m an idiot and didn’t think to take any.

And here’s the finished article:

It’s a bit tricky to see, since the screen blows out the lighting for the rest of the picture but it’s running google maps & spotify (and any other android apps really)

So that’s the centre console sorted, in my roadmap for future stuff I also have:

  • Android media streamers with touchscreens in the headrests for rear passengers
  • Powerfold mirrors (swing in when engine goes off)
  • Cooled / refrigerated cubby box

Oh, I also painted the front grill and a couple of other bits to improve the appearance, so here’s a lovely shot of how it looks currently:




Docker – add host.docker.internal on linux

Just a quick note (for my own memory more than anything)…

If you need to connect from a docker container to something running on your local host, it can be a bit of a pain on Linux. On windows & Mac, there’s a special DNS entry ‘host.docker.internal’ which always points to the host machine. However that isn’t available on Linux (here’s a bug open for this as of May 2018: https://github.com/docker/for-linux/issues/264)

That bug report also contains a pretty good solution for this problem, so to save you wading through, simply add the following line to your docker file:

RUN ip -4 route list match 0/0 | awk '{print $3 "host.docker.internal"}' >> /etc/hosts

That adds an entry to the container’s Host file, so host.docker.internal will resolve to your host just like it does on Mac / Windows.




e-Commerce building blocks

I’ve been working in e-commerce for a good few years now, for very similar companies (early stage, fast fashion focussed) and there’s always the same sorts of problems to solve. Here’s a very basic, very generic guide to the things you need to get up and running. Each bit has a ‘too long / didn’t read’ summary at the end, so you can just look for those if you don’t like reading. Please note that this is entirely my opinion, I don’t get paid by any of the companies I mention (although I am totally open to bribery. Seriously guys, hit me up.)

I’m going to split this up into a few different sections:

  1. Your website
  2. Your logistics (warehouse etc)
  3. Your customer service
  4. Internal IT / infrastructure
  5. Data / Reporting

First up…..




Merchandise magento category by product age / availability

Just a quick snippet of code today, it grabs all the products in a certain category (given in category_id), sorts them by age and stock availability (you can adjust the relative weighting of these using $stock_weight) and then updates the category. The end result is a nice mix of newer products, and products with loads of stock towards the top of the category, older / lower stocked products further down.

This uses the external database script access script from: here

I should probably bundle this up into an extension, with a cron job and so on but…. I’ll leave that as an exercise for the reader!


$category_id = 8;
$stock_weight = 10;


$sql = "select ccp.*, DATEDIFF(Now(),cpe.created_at) as age,
(select sum(qty) from cataloginventory_stock_item as csi join catalog_product_super_link as cpsl on csi.product_id = cpsl.product_id where cpsl.parent_id = cpe.entity_id) as stock_qty,
((select DATEDIFF(Now(),MIN(created_at)) from catalog_product_entity) - (select age)) as age_factor,
(select stock_qty) * $stock_weight as stock_factor,
(select age_factor) + (select stock_factor) as sortby
from catalog_category_product as ccp
	join catalog_product_entity as cpe
		on cpe.entity_id = ccp.product_id
where ccp.category_id = $category_id
and cpe.type_id = 'configurable'
ORDER BY sortby DESC";


function build_query($results){
  $update_sql = "Insert into catalog_category_product (`category_id`,`product_id`,`position`) VALUES ";
  $pos = 0;
  foreach($results as $result){
    $pos++;
    $update_sql .= "('".$result['category_id']."','".$result['product_id']."','".$pos."'),";
  }
  $update_sql = rtrim($update_sql,',');
  return $update_sql;
}


require_once "include/db.php";

$db = new db();

$results = $db->query($sql);
$db->query("delete from catalog_category_product where category_id = $category_id");
$db->query(build_query($results));








Access magento database outside magento

Just a quick note, sometimes you need to access the magento database from a script, but don’t want the overhead of loading the whole magento framework….. Here’s a little snippet of code that  grabs the database details from the magento xml config, so you don’t have to store them in your script:

<?php
 class db {

 private $data = null;


 public function __construct(){
     $xml=simplexml_load_file(realpath(dirname(__FILE__))."/../../app/etc/local.xml");

     $host = (string) $xml->global->resources->default_setup->connection->host;
     $db = (string) $xml->global->resources->default_setup->connection->dbname;
     $user =(string) $xml->global->resources->default_setup->connection->username;
     $pass = (string) $xml->global->resources->default_setup->connection->password;
     $charset = 'utf8mb4';

     $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
     $opt = [
         PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
         PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
         PDO::ATTR_EMULATE_PREPARES => false,
     ];
     $this->data = new PDO($dsn, $user, $pass, $opt);
 }

 public function query($sql){
    return $this->data->query($sql)->fetchAll(PDO::FETCH_ASSOC);
 }

 }

 ?>

Save it somewhere like /magento_root/scripts/include/db.php and use it like this:
 

<?php

require "include/db.php"
$db = new db();

$results = $db->query('select * from cataloginventory_stock_item');

?>

 

 

 




Mage Tools

Quick plug for some magento scripts I wrote for development / deployments of Magento 1.x

There’s some info in the readme, but I might write a couple of quick tutorials if anyone’s interested:

https://github.com/Tall-Paul/mage-tools




Dev tooling with docker

This is the first in what will become a series of articles on development processes and techniques in use at my current place of work, Public Desire.  To start off with I’m going to take a run through our docker based development environment, then in future articles I might dip into our deployment processes and testing.  In my usual fashion I’m going to stay away from delving too deeply into the concepts and technical gubbins underlaying Docker and concentrate on the pragmatic business of getting a dev environment up and running.  If you’ve wanted to give docker a try, but found it a little intimidating give this a shot….




Chuwi Hi10 Pro keyboard / trackpad fix

Hi there, been a long time… nearly 6 months since I last posted anything.  Having a kid will do that to ya!

Anyway, this week I picked myself up a nifty little 2 in 1 tablet / laptop thingy from a chinese manufacturer I’d never heard of: The Chuwi Hi10 pro. For a grand total of £190 (£20 of which was import duty) I got this little beauty (after waiting a couple of weeks for delivery)

chuwi




Bannr.io

For the last couple of months I’ve been working on a platform to solve one of the problems I’ve seen repeated across numerous businesses in the ‘fast fashion’ ecommerce space.  The problem is how to update your homepage and site with the numerous promotions you’re running in a timely fashion without impacting site performance.  For the majority of businesses in this space, Magento is the platform of choice for the web facing side of the business.  Unfortunately Magento’s tools for this particular problem are lacking.  Smaller businesses tend to use CMS blocks with javascript timers to make sure their promotions show at the right time.  Moving up the scale, we have plugins for magento that allow cms blocks to be shown on a schedule.  And at the top end of the cost spectrum we have ‘personalization’ platforms that, as well as offering variant testing and personalization also offer the ability to schedule blocks of content.




File injection and security breaking…..

I’ve just updated my dynamic proxy server in node.js to support file injection, and the stripping of headers that prevent loading targeted pages in iframes.  This may all sound very nefarious, but I actually require this functionality in a (super secret) project I’m working on….