Using $5 Open-Source Hardware for ChromeOS Enterprise enrollment and ChromeOS Flex installation

Author: Marc Evers

This guide will allow you to speed up and/or delegate Enterprise Enrollment of ChromeOS and ChromeOS flex devices* (e.g. for a POC) as well as automating a local install of ChromeOS flex (to convert a fleet of existing Windows or Mac OS devices).

If you are purchasing 100s of new devices, using Zero-Touch Enrollment is highly recommended.

Prerequisites:

  1. Google Admin account credentials with enrollment privileges. Demo Chrome can be used for testing and demonstration purposes.
  2. A ChromeOS or Windows device with a USB-A port
  3. One or more Digispark boards – currently only clones are available
    The search term is “ATTiny85 USB”. There are micro-USB (female) and USB-A (male PCB extension) variants. I chose the latter as it works without adapter cables in most devices.
  4. USB cables, extensions and/or hubs as appropriate
  5. command line, scripting or programming knowledge 

* Assumes functioning WiFi, timings may have to be adjusted for lower-spec flex devices.
Alternatively, you can use an ethernet connection or USB-ethernet adapter and skip the WiFi part by disabling that option.

Setting up the Arduino IDE

There is an excellent Chrome plug-in and a Progressive Web App available for programming and learning Arduino on ChromeOS. However, our (admittedly a little exotic) Digispark clone is not supported yet, so we have to install the “classic” IDE under Linux.

We’re tapping into the vast Arduino hardware and software ecosystem to program the board. The script or program is called a “sketch”. You will have to edit your details in it and upload it via the IDE.

Note: You can skip steps 1 & 2 and alter 4 if you are installing the IDE under Windows.

1) Enable Linux Development Environment

Go to Settings\Advanced\Developers in ChromeOS and enable the Linux Development Environment.
See Google Support for details.

2) Install the IDE

Open the new Terminal app and type/paste

sudo apt install arduino

Then press Enter.

Reply “y” to confirm installation and download. Once these complete you will see the Arduino IDE under “Linux apps”:

3) Install additional Boards Manager Packages

There are 100s of Arduino-compatible boards. To integrate the Digispark clone we need to install two packages by enabling the repositories inside the IDE.

Open the IDE and go to File\Preferences.

Paste

http://digistump.com/package_digistump_index.json, http://drazzy.com/package_drazzy.com_index.json

under Additional Boards Manager URLs. Note URLs are separated by a comma and a space.

Now go to Tools\Board:”Arduino Uno”(default)\Boards Manager

Search for and install Digistump AVR Boards (the original creator of the board, contains keyboard library)

And ATTinyCore (updated driver/bootloader for the microcontroller family, enables programming the clones as they have newer firmware installed)

Packages. Now close the IDE.

4) Enabling USB and Updating the Micronucleus Driver/Bootloader

As the Digispark is programmed via the USB port which it itself emulates in software(!) we have to perform some minor manual configuration. Thanks to Startingelectronics and the Arduino Stack Exchange community, which contain further details.

Open the Terminal if it’s not open still and paste the following commands, followed by Enter to confirm:

sudo nano /etc/udev/rules.d/49-micronucleus.rules

This opens the Nano text editor, paste

SUBSYSTEMS==”usb”, ATTRS{idVendor}==”16d0″, ATTRS{idProduct}==”0753″, MODE:=”0666″

KERNEL==”ttyACM*”, ATTRS{idVendor}==”16d0″, ATTRS{idProduct}==”0753″, MODE:=”0666″, ENV{ID_MM_DEVICE_IGNORE}=”1″

then press CTRL+O and CTRL+X to save and exit. Confirm any writes with “y”. 

Paste and confirm

sudo udevadm control –reload-rules

to apply the above.

Note: the next three commands may rely on differing paths if higher version numbers are installed. If you encounter errors, start typing and extend the commands by pressing  <TAB> twice at each step to see the options.

cd .arduino15/packages/digistump/tools/micronucleus/2.0a4

sudo mv -iv micronucleus micronucleus.backup

(renamed ‘micronucleus’ -> ‘micronucleus.backup’ should be returned)

sudo ln -s ~/.arduino15/packages/ATTinyCore/tools/micronucleus/2.5-azd1b/micronucleus

Uploading sketches

1) Testing the Board and IDE Config

Open the IDE again. The Boards selection now has two more sub-headings:

Select Digispark (Default – 16.5mhz) from Digistump AVR Boards. Note that the Programmer setting switches to “Micronucleus”, if not please revisit step 4. 

Now you are ready to try programming your board!

Delete all text and paste the Digistump Blink sketch (basic board test, will blink LED) into the IDE.


void setup() {                

  pinMode(0, OUTPUT);      // LED on Model B

  pinMode(1, OUTPUT);      // LED on Model A   

}

void loop() {

  digitalWrite(0, HIGH);   // Turn the LED on

  digitalWrite(1, HIGH);

  delay(1000);             // Wait for a second

  digitalWrite(0, LOW);    // Turn the LED off

  digitalWrite(1, LOW); 

  delay(1000);             // Wait for a second

}

You should save the sketch, e.g. as Digistump_blink.

To check your sketch click on the tick icon (Verify).

Have your board ready to plug in for the next step!

If there are no errors click on the arrow next to it (Upload). After compiling you have 60 seconds to plug the board in and connect it to Linux:

If successful, you should see something similar to the following:

The board’s LEDs will start blinking immediately after as long as it’s powered.

2) Modifying and uploading the Enrollment sketch 

Repeat the steps from 1) with the following sketch. You will have to edit it beforehand by adding your credentials and selecting which inputs you want to trigger. Also note differences in keyboard layout and other notes in the commented sections.

The sketch below has been tested on a Chromebook with a UK keyboard and ChromeOS v108, v109 & v110. 

/* modified from https://docs.google.com/document/d/1mtaGMOef8TFPNa5IiOVHR7HtHhwVfTP4w3QbS9j1vE0/edit?pli=1 */

/* Edit the following section with your details */

//WiFi

String ssid = “Wifi SSID”;

String ssid_password = “Password”;

//Chrome admin or enrollment account details, note

String email = “user.name\”demochrome.com”; /* use email@domain.org for US keyboard, replace @ with \” for UK or } for FR

/* we can install another library for a UK keyboard or just “fix” this one character as ” and @ are swapped between US and UK and we need to add \ to use the quote as a simple character */

String email_password = “[password]”;

//Enable (1) or disable (0) code sections = keyboard inputs, make sure the line ends with;

//ChromeVox popup, disable if you intend to be quick or disable it manually each time

int chromevox = 1;

//Wireless Setup Screen, disable if LAN is used

int wireless = 1;

//Enterprise Enrollment, you likely want this enabled

int enrollment = 1;

//Asset Identifier, disable if you want to give each asset a name manually

int asset = 1;

/* the next section contains other definitions */

#include <DigiKeyboard.h>

#define KEY_TAB 43

#define KEY_DOWN_ARROW  0x51

int keyWait = 275;

/* setup runs once */

void setup() {

// turn LEDs off

  digitalWrite(0, LOW);

  digitalWrite(1, LOW);

/* emulated keystrokes start here */

 //ChromeVox popup

 if(chromevox > 0){  

  DigiKeyboard.sendKeyStroke(0);

  wait(5);

  pressKey(KEY_TAB, 1);

  pressKey(KEY_ENTER, 1);

  }

 //Welcome Screen (defaults to “Get started”)

  wait(1);

  pressKey(KEY_ENTER, 1);

 //Wireless Setup Screen

 if(wireless > 0){

  pressKey(KEY_TAB, 3);

  pressKey(KEY_ENTER, 1);

  pressKey(KEY_TAB, 4);

  pressKey(KEY_ENTER, 1);

  pressKey(KEY_TAB, 3);

  pressKey(KEY_ENTER, 1);

  wait(2);

  DigiKeyboard.print(ssid);

  pressKey(KEY_TAB, 1);

  pressKey(KEY_ENTER, 1);

  pressKey(KEY_DOWN_ARROW, 2);

  pressKey(KEY_ENTER, 1);

  pressKey(KEY_TAB, 1);

  DigiKeyboard.print(ssid_password);

  pressKey(KEY_ENTER, 1);

  wait(10); //Wait to connect to wireless

  }

  //Next

  pressKey(KEY_TAB, 3);

  pressKey(KEY_ENTER, 1);

  wait(5);

 //Enterprise Enrollment

 if(enrollment>0) {

  pressKey(KEY_TAB, 2);

  pressKey(KEY_ENTER, 1);

  wait(5);

  pressKey(KEY_TAB, 8); // as email or phone is not effectively highlighted – can likely be skipped/removed in newer versions

  DigiKeyboard.print(email);

  pressKey(KEY_ENTER, 1);

  wait(4);

  DigiKeyboard.print(email_password);

  pressKey(KEY_ENTER, 1);

  }

 // Asset Identifier can be added manually, if not, this will Skip & select Done 

 if(asset > 0) {

  pressKey(KEY_TAB, 2);

  pressKey(KEY_ENTER, 1);

  wait(4);

  pressKey(KEY_ENTER, 1);

  }

//turn both LEDs on

  digitalWrite(0, HIGH);

  digitalWrite(1, HIGH);

}

/* loop is the main function as the microcontroller would run continuously */

void loop() {

}

//function definitions

uint8_t pressKey(uint8_t key, int times) {

  for (int i = 1; i <= times; i++) {

    DigiKeyboard.delay(50);

    DigiKeyboard.sendKeyStroke(key);

    DigiKeyboard.delay(keyWait);

  }

}

int wait(int seconds) {

  for (int i = 0; i < seconds; i++) {

    DigiKeyboard.delay(1000);

  }

}

3) Modifying and uploading the Flex Install sketch 

Repeat the steps from 1) with the Flex Install sketch below. This one has only two parameters, essentially a startup delay and test mode. The former depends on the type of device you’re converting and the speed of the USB drive.

If you want to convert a number of similar devices it’s worth timing the startup until the ChromeVox popup once.

The red LED will be on when the delay timer starts running(~7 seconds after power on), off while the keystrokes are passed to the OS and blinking once done. 

Also consider if you want to plug the Digispark board in separately or together with the USB drive you’re booting from (e.g. in a USB hub) and add some time for that. Note that more advanced hubs with e.g. HDMI and Ethernet interact with the OS and require you to plug in the Digispark board after the ChromeOS splash screen!

Again, check the notes in the commented sections of the sketch for more details.

The sketch below has been tested on a Dell XPS 13 9380 (F12 for boot menu) with a Kensington USB-C hub.

//Enable (1) or disable (0) code sections = keyboard inputs, make sure the line ends with;

//startup delay in seconds – note this is from the time the device is plugged in and powered. 420s gives you a very safe 7 minutes – 2 to plug in and select boot device and 5 for the OS boot from a slow drive

int startup = 420;

//Installation vs Test mode – go through with the final “Are you sure” popup

int reallyinstall = 0;

/* you can switch further modules off and on here to adjust for potential future GUI changes */

//ChromeVox popup, disable if you intend to be quick or disable it manually each time

int chromevox = 1;

/* the next section contains other definitions */

#include <DigiKeyboard.h>

#define KEY_TAB 43

#define KEY_DOWN_ARROW  0x51

int keyWait = 275;

/* setup runs once */

void setup() {

// turn LEDs on

  digitalWrite(0, HIGH);

  digitalWrite(1, HIGH);

 //Startup delay

 wait(startup);

 // turn LEDs off

  digitalWrite(0, LOW);

  digitalWrite(1, LOW);

 /* emulated keystrokes start here */ 

 //ChromeVox popup

 if(chromevox > 0){  

  DigiKeyboard.sendKeyStroke(0);

  wait(5);

  pressKey(KEY_TAB, 1);

  pressKey(KEY_ENTER, 1);

  }

 //Welcome Screen (defaults to “Get started”)

  DigiKeyboard.sendKeyStroke(0);

  wait(1);

  pressKey(KEY_ENTER, 1);

  wait(5);

 //Install Screen

  pressKey(KEY_TAB, 4); //Install

  pressKey(KEY_ENTER, 1); //tick

  pressKey(KEY_TAB, 1); //Next

  pressKey(KEY_ENTER, 1);  

  wait(5);

 //Install ChromeOS Flex

  pressKey(KEY_ENTER, 1);

  wait(5);

 // Confirmation popup

 if(reallyinstall > 0) {

  pressKey(KEY_TAB, 1);

  pressKey(KEY_ENTER, 1);

  }

}

/* loop is the main fuction as the microcontroller would run continuously */

/* this sketch will blink the LED (on either variant) as the screen might be off and more time might pass until you return to the device */

void loop() {

  digitalWrite(0, HIGH);   // Turn the LED on

  digitalWrite(1, HIGH);

  delay(1000);             // Wait for a second

  digitalWrite(0, LOW);    // Turn the LED off

  digitalWrite(1, LOW); 

  delay(1000);             // Wait for a second

  digitalWrite(0, HIGH);   // Turn the LED on

  digitalWrite(1, HIGH);

  delay(250);             // Wait for a quarter second

  digitalWrite(0, LOW);    // Turn the LED off

  digitalWrite(1, LOW); 

  delay(250);             // Wait for a quarter second

}

//function definitions

uint8_t pressKey(uint8_t key, int times) {

  for (int i = 1; i <= times; i++) {

    DigiKeyboard.delay(50);

    DigiKeyboard.sendKeyStroke(key);

    DigiKeyboard.delay(keyWait);

  }

}

int wait(int seconds) {

  for (int i = 0; i < seconds; i++) {

    DigiKeyboard.delay(1000);

  }

}

References::

https://docs.google.com/document/d/1mtaGMOef8TFPNa5IiOVHR7HtHhwVfTP4w3QbS9j1vE0

https://javiervidrua.github.io/blog/jekyll/update/2020/11/06/rubber-ducky-with-digispark-attiny85.html

https://logangreif.info/chromebook-setup/

http://digistump.com/products/1

Advertisement

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.