Tag Archives: king

Thumbnail

Building A Room Detector For IoT Devices On Mac OS




Building A Room Detector For IoT Devices On Mac OS

Alvin Wan



Knowing which room you’re in enables various IoT applications — from turning on the light to changing TV channels. So, how can we detect the moment you and your phone are in the kitchen, or bedroom, or living room? With today’s commodity hardware, there are a myriad of possibilities:

One solution is to equip each room with a bluetooth device. Once your phone is within range of a bluetooth device, your phone will know which room it is, based on the bluetooth device. However, maintaining an array of Bluetooth devices is significant overhead — from replacing batteries to replacing dysfunctional devices. Additionally, proximity to the Bluetooth device is not always the answer: if you’re in the living room, by the wall shared with the kitchen, your kitchen appliances should not start churning out food.

Another, albeit impractical, solution is to use GPS. However, keep in mind hat GPS works poorly indoors in which the multitude of walls, other signals, and other obstacles wreak havoc on GPS’s precision.

Our approach instead is to leverage all in-range WiFi networks — even the ones your phone is not connected to. Here is how: consider the strength of WiFi A in the kitchen; say it is 5. Since there is a wall between the kitchen and the bedroom, we can reasonably expect the strength of WiFi A in the bedroom to differ; say it is 2. We can exploit this difference to predict which room we’re in. What’s more: WiFi network B from our neighbor can only be detected from the living room but is effectively invisible from the kitchen. That makes prediction even easier. In sum, the list of all in-range WiFi gives us plentiful information.

This method has the distinct advantages of:

  1. not requiring more hardware;
  2. relying on more stable signals like WiFi;
  3. working well where other techniques such as GPS are weak.

The more walls the better, as the more disparate the WiFi network strengths, the easier the rooms are to classify. You will build a simple desktop app that collects data, learns from the data, and predicts which room you’re in at any given time.

Further Reading on SmashingMag:

Prerequisites

For this tutorial, you will need a Mac OSX. Whereas the code can apply to any platform, we will only provide dependency installation instructions for Mac.

Step 0: Setup Work Environment

Your desktop app will be written in NodeJS. However, to leverage more efficient computational libraries like numpy, the training and prediction code will be written in Python. To start, we will setup your environments and install dependencies. Create a new directory to house your project.

mkdir ~/riot

Navigate into the directory.

cd ~/riot

Use pip to install Python’s default virtual environment manager.

sudo pip install virtualenv

Create a Python3.6 virtual environment named riot.

virtualenv riot --python=python3.6

Activate the virtual environment.

source riot/bin/activate

Your prompt is now preceded by (riot). This indicates we have successfully entered the virtual environment. Install the following packages using pip:

  • numpy: An efficient, linear algebra library
  • scipy: A scientific computing library that implements popular machine learning models
pip install numpy==1.14.3 scipy
==1.1.0

With the working directory setup, we will start with a desktop app that records all WiFi networks in-range. These recordings will constitute training data for your machine learning model. Once we have data on hand, you will write a least squares classifier, trained on the WiFi signals collected earlier. Finally, we will use the least squares model to predict the room you’re in, based on the WiFi networks in range.

Step 1: Initial Desktop Application

In this step, we will create a new desktop application using Electron JS. To begin, we will instead the Node package manager npm and a download utility wget.

brew install npm wget

To begin, we will create a new Node project.

npm init

This prompts you for the package name and then the version number. Hit ENTER to accept the default name of riot and default version of 1.0.0.

package name: (riot)
version: (1.0.0)

This prompts you for a project description. Add any non-empty description you would like. Below, the description is room detector

description: room detector

This prompts you for the entry point, or the main file to run the project from. Enter app.js.

entry point: (index.js) app.js

This prompts you for the test command and git repository. Hit ENTER to skip these fields for now.

test command:
git repository:

This prompts you for keywords and author. Fill in any values you would like. Below, we use iot, wifi for keywords and use John Doe for the author.

keywords: iot,wifi
author: John Doe

This prompts you for the license. Hit ENTER to accept the default value of ISC.

license: (ISC)

At this point, npm will prompt you with a summary of information so far. Your output should be similar to the following.


  "name": "riot",
  "version": "1.0.0",
  "description": "room detector",
  "main": "app.js",
  "scripts": 
    "test": "echo "Error: no test specified" && exit 1"
  ,
  "keywords": [
    "iot",
    "wifi"
  ],
  "author": "John Doe",
  "license": "ISC"
}

Hit ENTER to accept. npm then produces a package.json. List all files to double-check.

ls

This will output the only file in this directory, along with the virtual environment folder.

package.json
riot

Install NodeJS dependencies for our project.

npm install electron --global  # makes electron binary accessible globally
npm install node-wifi --save

Start with main.js from Electron Quick Start, by downloading the file, using the below. The following -O argument renames main.js to app.js.

wget https://raw.githubusercontent.com/electron/electron-quick-start/master/main.js -O app.js

Open app.js in nano or your favorite text editor.

nano app.js

On line 12, change index.html to static/index.html, as we will create a directory static to contain all HTML templates.

function createWindow () 
  // Create the browser window.
  win = new BrowserWindow(width: 1200, height: 800)

  // and load the index.html of the app.
  win.loadFile('static/index.html')

  // Open the DevTools.

Save your changes and exit the editor. Your file should match the source code of the app.js file. Now create a new directory to house our HTML templates.

mkdir static

Download a stylesheet created for this project.

wget https://raw.githubusercontent.com/alvinwan/riot/master/static/style.css?token=AB-ObfDtD46ANlqrObDanckTQJ2Q1Pyuks5bf79PwA%3D%3D -O static/style.css

Open static/index.html in nano or your favorite text editor. Start with the standard HTML structure.

<!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8">
      <title>Riot | Room Detector</title>
    </head>
    <body>
      <main>
      </main>
    </body>
  </html>

Right after the title, link the Montserrat font linked by Google Fonts and stylesheet.

<title>Riot | Room Detector</title>
  <!-- start new code -->
  <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
  <link href="style.css" rel="stylesheet">
  <!-- end new code -->
</head>

Between the main tags, add a slot for the predicted room name.

<main>
  <!-- start new code -->
  <p class="text">I believe you’re in the</p>
  <h1 class="title" id="predicted-room-name">(I dunno)</h1>
  <!-- end new code -->
</main>

Your script should now match the following exactly. Exit the editor.

<!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8">
      <title>Riot | Room Detector</title>
      <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
      <link href="style.css" rel="stylesheet">
    </head>
    <body>
      <main>
        <p class="text">I believe you’re in the</p>
        <h1 class="title" id="predicted-room-name">(I dunno)</h1>
      </main>
    </body>
  </html>

Now, amend the package file to contain a start command.

nano package.json

Right after line 7, add a start command that’s aliased to electron .. Make sure to add a comma to the end of the previous line.

"scripts": 
  "test": "echo "Error: no test specified" && exit 1",
  "start": "electron ."
,

Save and exit. You are now ready to launch your desktop app in Electron JS. Use npm to launch your application.

npm start

Your desktop application should match the following.


home page with button


Home page with “Add New Room” button available (Large preview)

This completes your starting desktop app. To exit, navigate back to your terminal and CTRL+C. In the next step, we will record wifi networks, and make the recording utility accessible through the desktop application UI.

Step 2: Record WiFi Networks

In this step, you will write a NodeJS script that records the strength and frequency of all in-range wifi networks. Create a directory for your scripts.

mkdir scripts

Open scripts/observe.js in nano or your favorite text editor.

nano scripts/observe.js

Import a NodeJS wifi utility and the filesystem object.

var wifi = require('node-wifi');
var fs = require('fs');

Define a record function that accepts a completion handler.

/**
 * Uses a recursive function for repeated scans, since scans are asynchronous.
 */
function record(n, completion, hook) 

Inside the new function, initialize the wifi utility. Set iface to null to initialize to a random wifi interface, as this value is currently irrelevant.

function record(n, completion, hook) 
    wifi.init(
        iface : null
    );
}

Define an array to contain your samples. Samples are training data we will use for our model. The samples in this particular tutorial are lists of in-range wifi networks and their associated strengths, frequencies, names etc.

function record(n, completion, hook) 
    ...
    samples = []

Define a recursive function startScan, which will asynchronously initiate wifi scans. Upon completion, the asynchronous wifi scan will then recursively invoke startScan.

function record(n, completion, hook) 
  ...
  function startScan(i) 
    wifi.scan(function(err, networks) 
    );
  }
  startScan(n);
}

In the wifi.scan callback, check for errors or empty lists of networks and restart the scan if so.

wifi.scan(function(err, networks) 
  if (err 
});

Add the recursive function’s base case, which invokes the completion handler.

wifi.scan(function(err, networks) 
  ...
  if (i <= 0) 
    return completion(samples: samples);
  }
});

Output a progress update, append to the list of samples, and make the recursive call.

wifi.scan(function(err, networks) 
  ...
  hook(n-i+1, networks);
  samples.push(networks);
  startScan(i-1);
);

At the end of your file, invoke the record function with a callback that saves samples to a file on disk.

function record(completion) 
  ...


function cli() 
  record(1, function(data) 
    fs.writeFile('samples.json', JSON.stringify(data), 'utf8', function() );
  }, function(i, networks) 
    console.log(" * [INFO] Collected sample " + (21-i) + " with " + networks.length + " networks");
  )
}

cli();

Double check that your file matches the following:

var wifi = require('node-wifi');
var fs = require('fs');

/**
 * Uses a recursive function for repeated scans, since scans are asynchronous.
 */
function record(n, completion, hook) 
  wifi.init(
      iface : null // network interface, choose a random wifi interface if set to null
  );

  samples = []
  function startScan(i) 
    wifi.scan(function(err, networks) 
        if (err 
        if (i <= 0) 
          return completion(samples: samples);
        }
        hook(n-i+1, networks);
        samples.push(networks);
        startScan(i-1);
    });
  }

  startScan(n);
}

function cli() 
    record(1, function(data) 
        fs.writeFile('samples.json', JSON.stringify(data), 'utf8', function() );
    }, function(i, networks) 
        console.log(" * [INFO] Collected sample " + i + " with " + networks.length + " networks");
    )
}

cli();

Save and exit. Run the script.

node scripts/observe.js

Your output will match the following, with variable numbers of networks.

 * [INFO] Collected sample 1 with 39 networks

Examine the samples that were just collected. Pipe to json_pp to pretty print the JSON and pipe to head to view the first 16 lines.

cat samples.json | json_pp | head -16

The below is example output for a 2.4 GHz network.


  "samples": [
    [
      
        "mac": "64:0f:28:79:9a:29",
        "bssid": "64:0f:28:79:9a:29",
        "ssid": "SMASHINGMAGAZINEROCKS",
         "channel": 4,
         "frequency": 2427,
          "signal_level": "-91",
          "security": "WPA WPA2",
          "security_flags": [
           "(PSK/AES,TKIP/TKIP)",
          "(PSK/AES,TKIP/TKIP)"
        ]
      ,

This concludes your NodeJS wifi-scanning script. This allows us to view all in-range WiFi networks. In the next step, you will make this script accessible from the desktop app.

Step 3: Connect Scan Script To Desktop App

In this step, you will first add a button to the desktop app to trigger the script with. Then, you will update the desktop app UI with the script’s progress.

Open static/index.html.

nano static/index.html

Insert the “Add” button, as shown below.

<h1 class="title" id="predicted-room-name">(I dunno)</h1>
        <!-- start new code -->
        <div class="buttons">
            <a href="add.html" class="button">Add new room</a>
        </div>
        <!-- end new code -->
    </main>

Save and exit. Open static/add.html.

nano static/add.html

Paste the following content.

<!DOCTYPE html>
  <html>
    <head>
      <meta charset="UTF-8">
      <title>Riot | Add New Room</title>
      <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
      <link href="style.css" rel="stylesheet">
    </head>
    <body>
      <main>
        <h1 class="title" id="add-title">0</h1>
        <p class="subtitle">of <span>20</span> samples needed. Feel free to move around the room.</p>
        <input type="text" id="add-room-name" class="text-field" placeholder="(room name)">
        <div class="buttons">
          <a href="#" id="start-recording" class="button">Start recording</a>
          <a href="index.html" class="button light">Cancel</a>
        </div>
        <p class="text" id="add-status" style="display:none"></p>
      </main>
      <script>
        require('../scripts/observe.js')
      </script>
    </body>
  </html>

Save and exit. Reopen scripts/observe.js.

nano scripts/observe.js

Beneath the cli function, define a new ui function.

function cli() 
    ...


// start new code
function ui() 

// end new code

cli();

Update the desktop app status to indicate the function has started running.

function ui() 
  var room_name = document.querySelector('#add-room-name').value;
  var status = document.querySelector('#add-status');
  var number = document.querySelector('#add-title');
  status.style.display = "block"
  status.innerHTML = "Listening for wifi..."

Partition the data into training and validation data sets.

function ui() 
  ...
  function completion(data) 
    train_data = samples: data['samples'].slice(0, 15)
    test_data = samples: data['samples'].slice(15)
    var train_json = JSON.stringify(train_data);
    var test_json = JSON.stringify(test_data);
  }
}

Still within the completion callback, write both datasets to disk.

function ui() 
  ...
  function completion(data) 
    ...
    fs.writeFile('data/' + room_name + '_train.json', train_json, 'utf8', function() );
    fs.writeFile('data/' + room_name + '_test.json', test_json, 'utf8', function() {});
    console.log(" * [INFO] Done")
    status.innerHTML = "Done."
  }
}

Invoke record with the appropriate callbacks to record 20 samples and save the samples to disk.

function ui() 
  ...
  function completion(data) 
    ...
  
  record(20, completion, function(i, networks) 
    number.innerHTML = i
    console.log(" * [INFO] Collected sample " + i + " with " + networks.length + " networks")
  )
}

Finally, invoke the cli and ui functions where appropriate. Start by deleting the cli(); call at the bottom of the file.

function ui() 
    ...


cli();  // remove me

Check if the document object is globally accessible. If not, the script is being run from the command line. In this case, invoke the cli function. If it is, the script is loaded from within the desktop app. In this case, bind the click listener to the ui function.

if (typeof document == 'undefined') 
    cli();
 else 
    document.querySelector('#start-recording').addEventListener('click', ui)

Save and exit. Create a directory to hold our data.

mkdir data

Launch the desktop app.

npm start

You will see the following homepage. Click on “Add room”.




(Large preview)

You will see the following form. Type in a name for the room. Remember this name, as we will use this later on. Our example will be bedroom.


Add New Room page


“Add New Room” page on load (Large preview)

Click “Start recording,” and you will see the following status “Listening for wifi…”.


starting recording


“Add New Room” starting recording (Large Preview)

Once all 20 samples are recorded, your app will match the following. The status will read “Done.”




“Add New Room” page after recording is complete (Large preview)

Click on the misnamed “Cancel” to return to the homepage, which matches the following.


finished recording


“Add New Room” page after recording is complete (Large preview)

We can now scan wifi networks from the desktop UI, which will save all recorded samples to files on disk. Next, we will train an out-of-box machine learning algorithm-least squares on the data you have collected.

Step 4: Write Python Training Script

In this step, we will write a training script in Python. Create a directory for your training utilities.

mkdir model

Open model/train.py

nano model/train.py

At the top of your file, import the numpy computational library and scipy for its least squares model.

import numpy as np
from scipy.linalg import lstsq
import json
import sys

The next three utilities will handle loading and setting up data from the files on disk. Start by adding a utility function that flattens nested lists. You will use this to flatten a list of list of samples.

import sys

def flatten(list_of_lists):
    """Flatten a list of lists to make a list.
    >>> flatten([[1], [2], [3, 4]])
    [1, 2, 3, 4]
    """
    return sum(list_of_lists, [])

Add a second utility that loads samples from the specified files. This method abstracts away the fact that samples are spread out across multiple files, returning just a single generator for all samples. For each of the samples, the label is the index of the file. e.g., If you call get_all_samples('a.json', 'b.json'), all samples in a.json will have label 0 and all samples in b.json will have label 1.

def get_all_samples(paths):
  """Load all samples from JSON files."""
  for label, path in enumerate(paths):
  with open(path) as f:
    for sample in json.load(f)['samples']:
      signal_levels = [
        network['signal_level'].replace('RSSI', '') or 0
        for network in sample]
      yield [network['mac'] for network in sample], signal_levels, label

Next, add a utility that encodes the samples using a bag-of-words-esque model. Here is an example: Assume we collect two samples.

  1. wifi network A at strength 10 and wifi network B at strength 15
  2. wifi network B at strength 20 and wifi network C at strength 25.

This function will produce a list of three numbers for each of the samples: the first value is the strength of wifi network A, the second for network B, and the third for C. In effect, the format is [A, B, C].

  1. [10, 15, 0]
  2. [0, 20, 25]
def bag_of_words(all_networks, all_strengths, ordering):
  """Apply bag-of-words encoding to categorical variables.

  >>> samples = bag_of_words(
  ...     [['a', 'b'], ['b', 'c'], ['a', 'c']],
  ...     [[1, 2], [2, 3], [1, 3]],
  ...     ['a', 'b', 'c'])
  >>> next(samples)
  [1, 2, 0]
  >>> next(samples)
  [0, 2, 3]
  """
  for networks, strengths in zip(all_networks, all_strengths):
    yield [strengths[networks.index(network)]
      if network in networks else 0
      for network in ordering]

Using all three utilities above, we synthesize a collection of samples and their labels. Gather all samples and labels using get_all_samples. Define a consistent format ordering to one-hot encode all samples, then apply one_hot encoding to samples. Finally, construct the data and label matrices X and Y respectively.

def create_dataset(classpaths, ordering=None):
  """Create dataset from a list of paths to JSON files."""
  networks, strengths, labels = zip(*get_all_samples(classpaths))
  if ordering is None:
    ordering = list(sorted(set(flatten(networks))))
  X = np.array(list(bag_of_words(networks, strengths, ordering))).astype(np.float64)
  Y = np.array(list(labels)).astype(np.int)
  return X, Y, ordering

These functions complete the data pipeline. Next, we abstract away model prediction and evaluation. Start by defining the prediction method. The first function normalizes our model outputs, so that the sum of all values totals to 1 and that all values are non-negative; this ensures that the output is a valid probability distribution. The second evaluates the model.

def softmax(x):
  """Convert one-hotted outputs into probability distribution"""
  x = np.exp(x)
  return x / np.sum(x)


def predict(X, w):
  """Predict using model parameters"""
  return np.argmax(softmax(X.dot(w)), axis=1)

Next, evaluate the model’s accuracy. The first line runs prediction using the model. The second counts the numbers of times both predicted and true values agree, then normalizes by the total number of samples.

def evaluate(X, Y, w):
  """Evaluate model w on samples X and labels Y."""
  Y_pred = predict(X, w)
  accuracy = (Y == Y_pred).sum() / X.shape[0]
  return accuracy

This concludes our prediction and evaluation utilities. After these utilities, define a main function that will collect the dataset, train, and evaluate. Start by reading the list of arguments from the command line sys.argv; these are the rooms to include in training. Then create a large dataset from all of the specified rooms.

def main():
  classes = sys.argv[1:]

  train_paths = sorted(['data/{}_train.json'.format(name) for name in classes])
  test_paths = sorted(['data/{}_test.json'.format(name) for name in classes])
  X_train, Y_train, ordering = create_dataset(train_paths)
  X_test, Y_test, _ = create_dataset(test_paths, ordering=ordering)

Apply one-hot encoding to the labels. A one-hot encoding is similar to the bag-of-words model above; we use this encoding to handle categorical variables. Say we have 3 possible labels. Instead of labelling 1, 2, or 3, we label the data with [1, 0, 0], [0, 1, 0], or [0, 0, 1]. For this tutorial, we will spare the explanation for why one-hot encoding is important. Train the model, and evaluate on both the train and validation sets.

def main():
  ...
  X_test, Y_test, _ = create_dataset(test_paths, ordering=ordering)
  
  Y_train_oh = np.eye(len(classes))[Y_train]
  w, _, _, _ = lstsq(X_train, Y_train_oh)
  train_accuracy = evaluate(X_train, Y_train, w)
  test_accuracy = evaluate(X_test, Y_test, w)

Print both accuracies, and save the model to disk.

def main():
  ...
  print('Train accuracy ({}%), Validation accuracy ({}%)'.format(train_accuracy*100, test_accuracy*100))
  np.save('w.npy', w)
  np.save('ordering.npy', np.array(ordering))
  sys.stdout.flush()

At the end of the file, run the main function.

if __name__ == '__main__':
  main()

Save and exit. Double check that your file matches the following:

import numpy as np
from scipy.linalg import lstsq
import json
import sys


def flatten(list_of_lists):
    """Flatten a list of lists to make a list.
    >>> flatten([[1], [2], [3, 4]])
    [1, 2, 3, 4]
    """
    return sum(list_of_lists, [])


def get_all_samples(paths):
    """Load all samples from JSON files."""
    for label, path in enumerate(paths):
        with open(path) as f:
            for sample in json.load(f)['samples']:
                signal_levels = [
                    network['signal_level'].replace('RSSI', '') or 0
                    for network in sample]
                yield [network['mac'] for network in sample], signal_levels, label


def bag_of_words(all_networks, all_strengths, ordering):
    """Apply bag-of-words encoding to categorical variables.
    >>> samples = bag_of_words(
    ...     [['a', 'b'], ['b', 'c'], ['a', 'c']],
    ...     [[1, 2], [2, 3], [1, 3]],
    ...     ['a', 'b', 'c'])
    >>> next(samples)
    [1, 2, 0]
    >>> next(samples)
    [0, 2, 3]
    """
    for networks, strengths in zip(all_networks, all_strengths):
        yield [int(strengths[networks.index(network)])
            if network in networks else 0
            for network in ordering]


def create_dataset(classpaths, ordering=None):
    """Create dataset from a list of paths to JSON files."""
    networks, strengths, labels = zip(*get_all_samples(classpaths))
    if ordering is None:
        ordering = list(sorted(set(flatten(networks))))
    X = np.array(list(bag_of_words(networks, strengths, ordering))).astype(np.float64)
    Y = np.array(list(labels)).astype(np.int)
    return X, Y, ordering


def softmax(x):
    """Convert one-hotted outputs into probability distribution"""
    x = np.exp(x)
    return x / np.sum(x)


def predict(X, w):
    """Predict using model parameters"""
    return np.argmax(softmax(X.dot(w)), axis=1)


def evaluate(X, Y, w):
    """Evaluate model w on samples X and labels Y."""
    Y_pred = predict(X, w)
    accuracy = (Y == Y_pred).sum() / X.shape[0]
    return accuracy


def main():
    classes = sys.argv[1:]

    train_paths = sorted(['data/{}_train.json'.format(name) for name in classes])
    test_paths = sorted(['data/{}_test.json'.format(name) for name in classes])
    X_train, Y_train, ordering = create_dataset(train_paths)
    X_test, Y_test, _ = create_dataset(test_paths, ordering=ordering)

    Y_train_oh = np.eye(len(classes))[Y_train]
    w, _, _, _ = lstsq(X_train, Y_train_oh)
    train_accuracy = evaluate(X_train, Y_train, w)
    validation_accuracy = evaluate(X_test, Y_test, w)

    print('Train accuracy ({}%), Validation accuracy ({}%)'.format(train_accuracy*100, validation_accuracy*100))
    np.save('w.npy', w)
    np.save('ordering.npy', np.array(ordering))
    sys.stdout.flush()


if __name__ == '__main__':
    main()

Save and exit. Recall the room name used above when recording the 20 samples. Use that name instead of bedroom below. Our example is bedroom. We use -W ignore to ignore warnings from a LAPACK bug.

python -W ignore model/train.py bedroom

Since we’ve only collected training samples for one room, you should see 100% training and validation accuracies.

Train accuracy (100.0%), Validation accuracy (100.0%)

Next, we will link this training script to the desktop app.

In this step, we will automatically retrain the model whenever the user collects a new batch of samples. Open scripts/observe.js.

nano scripts/observe.js

Right after the fs import, import the child process spawner and utilities.

var fs = require('fs');
// start new code
const spawn = require("child_process").spawn;
var utils = require('./utils.js');

In the ui function, add the following call to retrain at the end of the completion handler.

function ui() 
  ...
  function completion() 
    ...
    retrain((data) => 
      var status = document.querySelector('#add-status');
      accuracies = data.toString().split('n')[0];
      status.innerHTML = "Retraining succeeded: " + accuracies
    );
  }
    ...
}

After the ui function, add the following retrain function. This spawns a child process that will run the python script. Upon completion, the process calls a completion handler. Upon failure, it will log the error message.

function ui() 
  ..


function retrain(completion) 
  var filenames = utils.get_filenames()
  const pythonProcess = spawn('python', ["./model/train.py"].concat(filenames));
  pythonProcess.stdout.on('data', completion);
  pythonProcess.stderr.on('data', (data) => 
    console.log(" * [ERROR] " + data.toString())
  )
}

Save and exit. Open scripts/utils.js.

nano scripts/utils.js

Add the following utility for fetching all datasets in data/.

var fs = require('fs');

module.exports = 
  get_filenames: get_filenames


function get_filenames() 
  filenames = new Set([]);
  fs.readdirSync("data/").forEach(function(filename) 
      filenames.add(filename.replace('_train', '').replace('_test', '').replace('.json', '' ))
  );
  filenames = Array.from(filenames.values())
  filenames.sort();
  filenames.splice(filenames.indexOf('.DS_Store'), 1)
  return filenames
}

Save and exit. For the conclusion of this step, physically move to a new location. There ideally should be a wall between your original location and your new location. The more barriers, the better your desktop app will work.

Once again, run your desktop app.

npm start

Just as before, run the training script. Click on “Add room”.


home page with button


Home page with “Add New Room” button available (Large preview)

Type in a room name that is different from your first room’s. We will use living room.


Add New Room page


“Add New Room” page on load (Large preview)

Click “Start recording,” and you will see the following status “Listening for wifi…”.




“Add New Room” starting recording for second room (Large preview)

Once all 20 samples are recorded, your app will match the following. The status will read “Done. Retraining model…”


finished recording 2


“Add New Room” page after recording for second room complete (Large preview)

In the next step, we will use this retrained model to predict the room you’re in, on the fly.

Step 6: Write Python Evaluation Script

In this step, we will load the pretrained model parameters, scan for wifi networks, and predict the room based on the scan.

Open model/eval.py.

nano model/eval.py

Import libraries used and defined in our last script.

import numpy as np
import sys
import json
import os
import json

from train import predict
from train import softmax
from train import create_dataset
from train import evaluate

Define a utility to extract the names of all datasets. This function assumes that all datasets are stored in data/ as <dataset>_train.json and <dataset>_test.json.

from train import evaluate

def get_datasets():
  """Extract dataset names."""
  return sorted(list(path.split('_')[0] for path in os.listdir('./data')
    if '.DS' not in path))

Define the main function, and start by loading parameters saved from the training script.

def get_datasets():
  ...

def main():
  w = np.load('w.npy')
  ordering = np.load('ordering.npy')

Create the dataset and predict.

def main():
  ...
  classpaths = [sys.argv[1]]
  X, _, _ = create_dataset(classpaths, ordering)
  y = np.asscalar(predict(X, w))

Compute a confidence score based on the difference between the top two probabilities.

def main():
  ...
  sorted_y = sorted(softmax(X.dot(w)).flatten())
  confidence = 1
  if len(sorted_y) > 1:
    confidence = round(sorted_y[-1] - sorted_y[-2], 2)

Finally, extract the category and print the result. To conclude the script, invoke the main function.

def main()
  ...
  category = get_datasets()[y]
  print(json.dumps("category": category, "confidence": confidence))

if __name__ == '__main__':
  main()

Save and exit. Double check your code matches the following (source code):

import numpy as np
import sys
import json
import os
import json

from train import predict
from train import softmax
from train import create_dataset
from train import evaluate


def get_datasets():
    """Extract dataset names."""
    return sorted(list(path.split('_')[0] for path in os.listdir('./data')
        if '.DS' not in path))


def main():
    w = np.load('w.npy')
    ordering = np.load('ordering.npy')

    classpaths = [sys.argv[1]]
    X, _, _ = create_dataset(classpaths, ordering)
    y = np.asscalar(predict(X, w))

    sorted_y = sorted(softmax(X.dot(w)).flatten())
    confidence = 1
    if len(sorted_y) > 1:
        confidence = round(sorted_y[-1] - sorted_y[-2], 2)

    category = get_datasets()[y]
    print(json.dumps("category": category, "confidence": confidence))


if __name__ == '__main__':
    main()

Next, we will connect this evaluation script to the desktop app. The desktop app will continuously run wifi scans and update the UI with the predicted room.

Step 7: Connect Evaluation To Desktop App

In this step, we will update the UI with a “confidence” display. Then, the associated NodeJS script will continuously run scans and predictions, updating the UI accordingly.

Open static/index.html.

nano static/index.html

Add a line for confidence right after the title and before the buttons.

<h1 class="title" id="predicted-room-name">(I dunno)</h1>
<!-- start new code -->
<p class="subtitle">with <span id="predicted-confidence">0%</span> confidence</p>
<!-- end new code -->
<div class="buttons">

Right after main but before the end of the body, add a new script predict.js.

</main>
  <!-- start new code -->
  <script>
  require('../scripts/predict.js')
  </script>
  <!-- end new code -->
</body>

Save and exit. Open scripts/predict.js.

nano scripts/predict.js

Import the needed NodeJS utilities for the filesystem, utilities, and child process spawner.

var fs = require('fs');
var utils = require('./utils');
const spawn = require("child_process").spawn;

Define a predict function which invokes a separate node process to detect wifi networks and a separate Python process to predict the room.

function predict(completion) 
  const nodeProcess = spawn('node', ["scripts/observe.js"]);
  const pythonProcess = spawn('python', ["-W", "ignore", "./model/eval.py", "samples.json"]);

After both processes have spawned, add callbacks to the Python process for both successes and errors. The success callback logs information, invokes the completion callback, and updates the UI with the prediction and confidence. The error callback logs the error.

function predict(completion) 
  ...
  pythonProcess.stdout.on('data', (data) => 
    information = JSON.parse(data.toString());
    console.log(" * [INFO] Room '" + information.category + "' with confidence '" + information.confidence + "'")
    completion()

    if (typeof document != "undefined") 
      document.querySelector('#predicted-room-name').innerHTML = information.category
      document.querySelector('#predicted-confidence').innerHTML = information.confidence
    
  });
  pythonProcess.stderr.on('data', (data) => 
    console.log(data.toString());
  )
}

Define a main function to invoke the predict function recursively, forever.

function main() 
  f = function()  predict(f) 
  predict(f)
}

main();

One last time, open the desktop app to see the live prediction.

npm start

Approximately every second, a scan will be completed and the interface will be updated with the latest confidence and predicted room. Congratulations; you have completed a simple room detector based on all in-range WiFi networks.

demo
Recording 20 samples inside the room and another 20 out in the hallway. Upon walking back inside, the script correctly predicts “hallway” then “bedroom.” (Large preview)

Conclusion

In this tutorial, we created a solution using only your desktop to detect your location within a building. We built a simple desktop app using Electron JS and applied a simple machine learning method on all in-range WiFi networks. This paves the way for Internet-of-things applications without the need for arrays of devices that are costly to maintain (cost not in terms of money but in terms of time and development).

Note: You can see the source code in its entirety on Github.

With time, you may find that this least squares does not perform spectacularly in fact. Try finding two locations within a single room, or stand in doorways. Least squares will be large unable to distinguish between edge cases. Can we do better? It turns out that we can, and in future lessons, we will leverage other techniques and the fundamentals of machine learning to better performance. This tutorial serves as a quick test bed for experiments to come.

Smashing Editorial
(ra, il)


This article is from - 

Building A Room Detector For IoT Devices On Mac OS

Thumbnail

8 Surefire Strategies to Boost Your Blog Conversions

blog-conversions-featured

In 2018, marketers are competing for an audience share that is both smart and digitally savvy. That means they can’t rely on the same old marketing strategy to carry blog conversions. If you’ve noticed stagnation in your conversion rate, it may be time to revise your strategy to boost conversions and keep your business growing. Be sure you’re incorporating these eight proven techniques to maximize your blog conversions. 1. Know your Target The most obvious element in conversion is a laser-like focus on the users you’re aiming to attract and convert. Are you posting articles like mad, but lacking the…

The post 8 Surefire Strategies to Boost Your Blog Conversions appeared first on The Daily Egg.

Originally posted here:  

8 Surefire Strategies to Boost Your Blog Conversions

Thumbnail

How to Use a Website Click Tracking Tool to Know your Audience

When it comes to understanding your audience, you can’t get more granular than a website click tracking tool. Instead of looking at big-picture metrics, you can drill down to the basics and get to know what works with your audience — and what doesn’t. Lots of site tracking tools exist, but website click tracking tools offer the most depth when you want to better understand user behavior. To see what I mean, visit a website you’ve never seen before. Just Google a broad topic, such as “marathon training” or “best thriller novels.” It doesn’t matter. Click on one of the…

The post How to Use a Website Click Tracking Tool to Know your Audience appeared first on The Daily Egg.

Source:

How to Use a Website Click Tracking Tool to Know your Audience

Thumbnail

How to Use a Website Click Tracking Tool to Improve the User Experience

When it comes to understanding your audience, you can’t get more granular than a website click tracking tool. Instead of looking at big picture metrics, you can drill down to the basics and get to know what works with your audience — and what doesn’t. While many site tracking tools exist, website click tracking tools offer the most depth when you want to better understand user behavior. To see what I mean, visit a website you’ve never been to before. Just Google a broad topic such as “marathon training” or “best thriller novels.” It doesn’t matter. Click on one of…

The post How to Use a Website Click Tracking Tool to Improve the User Experience appeared first on The Daily Egg.

Jump to original: 

How to Use a Website Click Tracking Tool to Improve the User Experience

Thumbnail

CRO Hero: Claire Peña, Growth Marketing Manager at Splunk

CRO Heroes

Admittedly, Conversion Rate Optimization is not the most sexy term in the marketing world – but if you’ve ever run an A/B test where the variant won by a landslide, or made a website design change that led to a significant increase in product purchases, you know firsthand how exciting and powerful CRO can be in action. Marketers who specialize in conversion rate optimization are often a rare mix of analytical and creative; tactical, and intuitive. They need to get inside a customer’s head, but they also need to dive deep into data. Often, CRO professionals are tasked with: Reducing…

The post CRO Hero: Claire Peña, Growth Marketing Manager at Splunk appeared first on The Daily Egg.

Link to original – 

CRO Hero: Claire Peña, Growth Marketing Manager at Splunk

Thumbnail

Making Distributed Product Teams Work More Efficiently With monday.com




Making Distributed Product Teams Work More Efficiently With monday.com

Nick Babich



(This is a sponsored article.) The way that product teams work is changing: The software industry is quickly moving to remote work. In the US alone, 43% of employed Americans have spent at least some time working remotely, and that number has steadily increased in recent years. Many successful digital products on the market today were designed and developed by a distributed team. Such teams don’t have an office in the traditional sense. Everyone chooses to work from where they like, both geographically and functionally (in a coworking space, coffee shop, home office, etc.).

While a distributed product team might sound tempting to you, creating an effective design process on such a team requires a lot of effort. Collaboration and communication are two of the most significant challenges distributed teams face. Managing a distributed team requires an understanding of how the individuals on your team operate, as well as requires a digital toolset that makes the team’s operations as efficient as possible. That’s why investing in the right remote tools and technology is so critical for product managers.

If you’re a team manager who is looking to establish a robust design process for a distributed team, then this article for you. You’ll find seven of the most common challenges distributed product teams should overcome and learn how a team-management tool called monday.com (formerly dapulse) can help them with that.

1. Build A Shared Understanding Of A Project’s Goals

When it comes to organizing a work process on a remote team, one of the key goals is to keep the whole team on the same page. Management needs to set goals and make sure everyone on the team understands and accepts them. Building understanding is especially important on remote teams because interaction tend to be more sporadic. Ensure that everyone on the team knows the following:

  • What are the project’s overall goals? When a team clearly understand’s the product strategy (what they want to build and why), that understanding motivates engagement.

  • What is expected of them, and how do they fit in the bigger picture? People want to know their role in the process. Even though every team member will be deep in the details when working on a project, understanding the big picture will help them to focus on what’s really important.

  • What are other people involved in the project doing? Each team member should have visibility on what the other team members are working on.

The more everyone knows, the better they can work as a team.

Visualize The Product Development Process

Helping everyone on the team know what is expected of them and when is possible using monday.com’s feature named the “timeline.” The timeline makes tasks more visual — team members will be able to see when each task is scheduled for, how long it will take and how it fits in the entire project. The tool enables you to see not only what tasks your team members are working on, but also how those tasks are distributed over time. It is great for when some activities depend on others (for example, developers are waiting on mockups from designers).


The timeline enables team members to see a high-level roadmap.


The timeline enables team members to see a high-level roadmap. (Large preview)

2. Manage The Team’s Workload

As anyone who has ever worked on a remote team will tell you, remote working is quite different from working face to face. Many project managers find it hard to manage the team’s workload.

Most product teams use project-tracking software to plan and estimate their work. Usually, a team will prepare all of the work in a task list, in which each task has a text description and a time estimate. The biggest downside of this approach is that it’s not very representative. For example, Kanban boards, used by many product teams today, are not very representative — it’s almost impossible from a glance at the board to understand the order in which tasks should be completed, especially when they have dependencies.


Using a Kanban board might make it hard to see how tasks should be distributed in time.


Using a Kanban board might make it hard to see how tasks should be distributed in time. (Image source) (Large preview)

Track Everything Your Team Is Working On

Interaction cost (i.e. the cognitive or physical effort required to complete an action) plays a vital role in the user experience of a product. The more effort required to complete an operation, the less usable the interface becomes for the end user. If the project manager has to switch to different products to see the team’s progress, that will create unnecessary friction and hinder the team from working efficiently.

monday.com assembles and displays progress data in a logical and understandable way. The tool has a feature called a board. The board is where all team members can track everything the team is working on. The main advantage of the board is that it enables product managers to monitor the team’s progress in real time and instantly see who is working on what and see where things stand.


monday.com gives you a clear sense of what needs to get done and who is responsible for what. The board provides in-depth insight into a project and its tasks.


monday.com gives you a clear sense of what needs to get done and who is responsible for what. The board provides in-depth insight into a project and its tasks. (Large preview)

Communicate Current Status

Each team needs a mechanism that makes it easy to understand what’s going on at a glance.

One way to solve this problem is to use color coding for different elements. Color coding speeds up visual search because it allows users to quickly filter a particular object (or objects) by knowing the color associated with it. monday.com uses color coding to indicate the current status of a task. For example, it’s easy to see where things have gotten stuck just by looking at the board and finding all tasks colored in red.


Status updates can be color coded.


Status updates can be color coded. (Large preview)

Create, Modify And Assign Tasks In A Few Clicks

Adding tasks in a project-management tool doesn’t sound very exciting. Generally, the more time it takes, the less happy the product manager will be.

monday.com simplifies the process of data input. Managers can quickly add rows to the board — monday.com calls them pulses. Pulses can be tasks, projects, missions, to-do items, etc. Creating a pulse requires just a few clicks.


Monday.com simplifies the process of data input. Managers can quickly add rows to the board — Monday.com calls them pulses. Pulses can be tasks, projects, missions, to-do items, etc. Creating a pulse requires just a few clicks.


(Large preview)

After you create a pulse, simply assign it to a team member.


Assign teammates to particular tasks or projects.


Assign teammates to particular tasks or projects. (Large preview)

Tailor The Platform To Your Needs

There’s no such thing as a universal design process. Every project is different and requires its own design process. A product-management tool should be very adaptive to change; the product team should be able to customize the process according to their needs, without having to put much effort into customization.

monday.com is extremely customizable and lets the user configure almost any option. You can customize monday.com to manage any workflow or process, to address any challenge and to manage basically anything.

When it comes to creating a board, you don’t need to start from scratch. A multitude of templates allow you to start quickly. For example, the “Team Tasks” template would be very useful for product teams.


Finding the right template for your activity is really simple because all templates are visualized.


Finding the right template for your activity is really simple because all templates are visualized. (Large preview)

After selecting a template for your needs, you can customize it by manipulating different sections. Product teams often need to combine task into groups, whereby each group represents a milestone (for example, “Release 1”, “Release 2”, etc.). Doing this in monday.com is relatively simple. As a board owner, you can have as many groups as you want.


Easy to organize tasks. You can have as many groups as you want.


Easy to organize tasks. You can have as many groups as you want. (Large preview)

But it doesn’t stop there. You can use the checklist feature to break down tasks even further. For example, each task can be broken down into smaller to-do steps. This feature is handy when a few activities need to get done before the task can be completed — for example, if a product specification needs to be approved by a few designers before it can be handed over to the development team. The checklist sits within a pulse, in the “Updates” section, and can help create a structure for each pulse.

The checklist sits within a pulse, in the “Updates” section. This feature can help create a structure for each pulse.
The checklist sits within a pulse, in the “Updates” section. This feature can help create a structure for each pulse. (Large preview)

Plan The Team’s Workload Visually

Designers, developers and managers often work with compressed timeframes and simultaneous projects. A team must be able to respond quickly to feedback on their product from stakeholders and users. Following the build-measure-learn cycle, a product team should be really flexible; it should be ready to implement feedback from testing sessions and adjust the design process according to the new information. The same level of flexibility should be in all products the team uses.

Using monday.com’s timeline, it’s possible to make corrections and improve the team’s efficiency. The visual editor makes the process of managing tasks easy. The product manager can see where each project is at each point, and can see and focus on areas of struggle, quickly and effectively.

The timeline makes it possible to see each team member’s capacity over a set period of time (say, the next few weeks), seeing where they have room to take on more work and where they need to delegate tasks to others.

Change the time range in the timeline. The time range is updated in real time.
Change the time range in the timeline. The time range is updated in real time. (Large preview)

3. Create Effective Internal Communications

Communication plays a critical role in the design process. When it comes to product design, it’s essential for all team members to be on the same page. Unlike colocated teams, a distributed team won’t have an opportunity to arrange regular face-to-face meetings. When you take out face-to-face interaction, you can’t expect things to just work the same way. Poorly established communication patterns can lead to some team members feeling like they’re working in a vacuum.

Tools matter more in remote work because they are the foundation for communication. The goal is to make sure everyone on the team feels connected.

Centralize All Communication

In today’s world, we communicate with a variety of tools: from traditional email to online messengers such as Skype, WhatsApp, Slack and Facebook Messenger. Having to switch from a task-management tool to another tool for communication can be stressful. Worse, some information can get lost during the transition (for example, an email inbox can fill up to the point that a team member can overlook a critical email).

Product teams can use monday.com as a single communication platform for their workplace. And it would be a much better solution because it allows for communication in the context of each task. With monday.com, you no longer need to use email for internal communication. When a team member clicks on a pulse on any board, a box opens to the right of the screen, showing the “updates”. Simply mention a person’s username (“@johndoe”), and send your message. The great thing is that the chat thread stays with that task, so finding a conversation after a while is relatively easy.

Cut Down On Meetings And Optimize Required Meetings

Meetings are an essential part of the communication process. When it comes to reviewing plans and brainstorming on design decisions, there’s no substitute for a meeting. But for a distributed team, the number of potential hours available for real-time meetings can be limited, so it’s essential to make the best use of that time. A distributed team should continually try to reduce their number of meetings and maximize the effectiveness of the time that team members have together.

Take a weekly kickoff meeting as an example. This meeting happens on a Monday, and team members come together to discuss plans for the week. For many teams, such meetings are rarely productive. Quite often, the information shared in a weekly kickoff meeting becomes outdated shortly after the meeting, and team members need to reprioritize tasks.

monday.com saves the team vast amounts of time in meetings. Instead of discussing the plan for the week, the product manager can break down complex tasks into weekly achievable goals. This will help team members plan the week based on what they need to get done.


Create a weekly task board.


Create a weekly task board. (Large preview)

Share Valuable Resources With The Entire Team, Not Individual Members

Imagine you’ve found a really valuable resource and want to share it with your peers. You tweet about it and send a link to a group chat. You get feedback like, “Awesome resource! Thanks!” from some people in the chat. Shortly after, most of your peers forget about the resource, especially if they can’t use it in the work they’re doing right now. Sad, right? We can do better.

Instead of sending a link to a group chat, share all resources you find on a separate board. monday.com has a template named “Design Inspiration & Resources”. The great thing about this approach is that it’ll be much easier for team members to find a particular resource when they actually need it.


Instead of sending a link to a group chat, share all resources you find on a separate board.


(Large preview)

Organize Better Planning And Brainstorming Sessions

Task prioritization is a typical activity in agile project management. Team members get together, discuss tasks and vote on what to implement in the next sprint.

monday.com incorporates voting. Team members can use the voting column when they want to decide on something together as a team. Simply add a voting column to a board, and team members will be able to cast their vote in one click.


Vote for ideas during brainstorming and planning sessions.


Vote for ideas during brainstorming and planning sessions. (Large preview)

Notify Team Members In Real Time

Fear of missing out (FOMO) is a common problem on distributed teams. When working remotely, team members might be afraid to miss an important piece of information. As a result, they spend a lot of time in communication tools, checking mail and messengers. This can get really distracting. Team members should spend less time in communication tools and more time in tools they use to design (tools for prototyping and development). It’s all too easy to waste the day reading messages and replying.

A communication tool should serve vital information just when team members need it; it should have an effective mechanism of notification. monday.com notifies users via desktop and mobile in real time. The platform has an app for iOS and Android. The app allows team members to stay connected on their phone or tablet and to respond quickly from anywhere. It’s also possible to customize notification rules. For example, you can manage which activity triggers an email.


Mention people or entire teams.


(Large preview)

Create A Work Schedule For Your Team

If your team is distributed across the globe and you need to arrange a meeting, you have to be sure that it won’t happen at awkward hours (such as in the middle of the night). It would be great to see the team members’ working hours.

The work schedule board is a cornerstone of your business operations. Team members in each time zone can commit to the times that work for them. This helps product managers schedule meetings at times that work for everybody.


The work schedule board shows when team members will be online and available for chat.


The work schedule board shows when team members will be online and available for chat. (Large preview)

4. Involve Users In The Design Process

Most commercially successful products were created with a strong focus on the target audience. Designers know that if they want to release a successful product, they need to introduce real users to the design process. User involvement is most efficient and influential in the early stages of product development, because the cost of making changes increases as the system develops. Generally, the earlier you create a strong feedback loop, the better the final product will be.

Share Designs With Users And Gather A Valuable Feedback

The feedback that a product team gets from users is extremely valuable. It can validate that the design team is moving in the right direction.

On monday.com, users can create a board and choose whom to share it with. For example, if you are working with a client, you can set up a board for their project and invite them to work as a guest. The board could include key features you want to work on. As soon as you share the board, the client will get a notification and then can open the board, review the plan and request modifications.

5. Find All Required Information Easily

Documentation is another challenge. Distributed teams don’t have a physically shared space where they can share product documentation. Information might be stored in many different places: email, cloud drives, local computers, etc. It could lead to team members missing an important piece of information and being unaware of it. This leads to fragmented knowledge.

Centralize All Documents

Having all documents in one place is critical to success. monday.com syncs all information in a single accessible hub. All team members can store all relevant discussions in a searchable database. The platform provides an option to upload different types of files simply by dragging and dropping. The next time a designer needs to share a product’s specifications, all they need to do is upload a file to the platform.


Upload all assets by dragging and dropping.


Upload all assets by dragging and dropping. (Large preview)

Search Anything And Everything

Anyone who has ever worked with a knowledge base will tell you how critical search functionality is. Without proper search, your chance of finding information decreases significantly.

monday.com allows you to quickly find anything your team has ever worked on, including images, updates, projects and assignments. Your work becomes a rich knowledge base.


monday.com allows you to quickly find anything your team has ever worked on, including images, updates, projects and assignments. Your work becomes a rich knowledge base.


(Large preview)

For example, when you need to find the latest version of a product’s specification, all you need to do is click the search box, select the “Files” tab and enter the project’s name as a search query.


When you need to find the latest version of a product’s specification, all you need to do is click the search box, select the ‘Files’ tab and enter the project’s name as a search query.


(Large preview)

6. Make The Collaboration Tool A Natural Part Of The Team

The platform you choose for team management should feel like second nature. Technology should work for you and your team, not the other way around.

Minimize The Time Required To Learn A Tool

When you introduce a new tool in the design process, one goal should be to have total agreement to work using this tool. This agreement is not always easy to come by because team members are usually skeptical about the next “magical tool that will solve all of their problems”. What’s worse is that they have to spend extra time learning how to use it. Nobody wants to learn new software.

One of the most significant advantages of monday.com is its intuitiveness. Regardless of whether you’ve used a similar app before, monday.com can be picked up with no training. Team members will be able to understand how to use the tool without preparation.


monday.com provides basic onboarding to help users get started.


monday.com provides basic onboarding to help users get started. (Large preview)

Scalable

When companies select a collaboration tool, they often think of it as an investment. They want a tool that will scale with the business.

monday.com is suitable for any sized team, from two freelancers working together to thousands collaborating across the globe. The tool scales with you, from simplicity to complexity, with total ease. Also, as your business expands, monday.com makes it painless to shift to a premium version (Standard, Pro or Enterprise) and get more of the platform’s premium features.

Integrate The Platform With Existing Tools

A task-management tool is essential for any team hoping for good results. But the team’s toolbox also needs to support the design process (for prototyping and development) and the collection of design artifacts (for example, on Google Drive or Dropbox). It’s essential that the team-management tool integrates seamlessly with other tools the team uses.

When it comes to integration, monday.com does a lot to be part of the established software ecosystem. It can connect to Dropbox, Zapier, Google Drive and other sharing tools. As a team member, you can attach a mockup file to your updates, sharing it in the context of the tasks it relates to.

monday.com also comes with an open API architecture, which lets developers build their own integrations.


Monday also comes with an open API architecture, which lets developers build their own integrations.


(Large preview)

7. Keep The Team Motivated

Having the right atmosphere is extremely important. Team leaders should not only be in tune with each person on the team, but should continually look for ways to increase engagement.

Celebrate Successes With Team Members

It’s natural for people to seek acknowledgment. The need for social approval drives us to look for confirmation from people we know (parents, friends, colleagues). When someone recognizes our results by saying something as simple as “Great job!”, we feel motivated to work towards our goals. It’s essential for team players to get acknowledged, especially when working remotely.

monday.com has a few features that help create a sense of acknowledgment. The first one is the thumb-up feature, which is basically a positive reaction to an activity. Most people are familiar with this from social networks. People are used to measuring the effect of a post by the number of likes they get. monday.com allows you to give a thumb up to your teammates’ work.


Monday has a few features that help create a sense of acknowledgment.


(Large preview)

Another nice feature are the animated GIFs. You can liven up comments with GIFs. monday.com lets you pick from thousands of GIFs when responding to teammates, which will add a bit of personality to your comments.

You can liven up comments with GIFs. Monday lets you pick from thousands of GIFs when responding to teammates, which will add a bit of personality to your comments.
(Large preview)

Last but not least, monday.com has a confetti feature. As soon as a designer completes their last “in progress” task on a board, they will see an animated confetti effect. This subtle detail adds a bit of delight and motivates team members to have an all-green board.

Monday has a confetti feature
(Large preview)

Conclusion

Establishing an effective process on a distributed team is hard. What works for a colocated team won’t necessarily work for a distributed team, and what works for one distributed team won’t necessarily work for another.

Build a remote-friendly work culture by focusing on following priorities:

  • Prioritize transparency.
    Keep important information accessible to everyone.

  • Stay on top of the team’s activity.
    Understand what every member of your team is doing and where the team is in the process at a glance.

  • Build an effective communication system.
    The foundation of distributed teams is communication. Create a healthy system of meetings and habits to keep people communicating.

  • Lower the barrier to entry.
    Choose a team-collaboration tool that will be the least painful for everyone to get on board with. It should be a reference point that brings everything together.

Smashing Editorial
(ms, ra, il, al)


Continue reading here:

Making Distributed Product Teams Work More Efficiently With monday.com

Thumbnail

Designing The Invisible: 3 Things I Learned Designing For Voice




Designing The Invisible: 3 Things I Learned Designing For Voice

William Merrill



The current iteration of voice-controlled digital assistants are still struggling to integrate as seamlessly as the big three voice players of Amazon, Google and Apple would hope. A 2017 report by Voicelabs states there’s only a 3 percent chance a user will be active in the second week after downloading a voice application and 62 percent of Alexa’s skills are still to get any kind of rating on its store (as of September 2017).

As designers, we have a real opportunity to provide valuable meaning to these assistants but we’re still trying to work out where the technology can add real benefits to the user. For many, embarking on a voice UI (VUI) project can be a bit like entering the Unknown. There are few success stories for designers or engineers to be inspired by, especially within contexts that illustrate how this nascent technology could help people thrive in new ways.

Experimenting With speechSynthesis

The Web Speech API gives you the ability to voice-enable your website in two directions: listening to your users via the SpeechRecognition interface and talking back to them via the speechSynthesis interface. All of this is done via a JavaScript API, making it easy to test for support. Read article →

As part of BBC2’s Big Life Fix docuseries where teams of inventors create new and life-changing solutions for people in need, I had the opportunity to test and build a voice-controlled assistant for a woman called Susan. Susan has been living with a progressive form of Multiple Sclerosis for over 20 years and is now unable to complete everyday tasks for herself easily. With full-time carers, she relies on others to wash and dress her and has no ability to even change the channel on the TV without help.

While voice technology seemed like it would provide the smoothest pathway to overcoming Susan’s physical difficulties, Susan has never used a smartphone, so propelling her straight into an interaction with a voice assistant was never going to be easy — we had to think cleverly to help her learn to communicate with an incredibly alien technology.

The result for Susan is a highly customized voice-controlled assistant that now empowers her to complete everyday tasks with the freedom that others take for granted — from making a phone call to family, to listening to music. Built as an enhanced version of Amazon Alexa technology on their Echo Dot device, Susan’s voice assistant also involved physical customization as we 3D printed a casing in the shape of her favorite animal, an owl.

As we rapidly experimented and iterated on a solution for Susan, my team and I uncovered dozens of intricacies that come with designing for voice in a more inclusive and accessible way. Although it was a unique project, there were three key takeaways that are applicable to any VUI project.

1. Make It Personal

The tech works. It’s not just a matter of sitting back and waiting for computing power to increase in line with user expectation. We found the voice detection, recognition, and synthesis of each of the devices far more powerful than we anticipated. And it’s not as though there’s a lack of choice. There are over 30,000 Alexa skills on Amazon with an average of 50 new ones being published daily. Skills are specific capabilities that enable designers and developers to create a more personalized voice experience when using devices like the Amazon Echo Dot. They operate much like an app within the App store on your smartphone, allowing you to customize your voice assistant the way you please.

However, there currently is a big barrier to access. Skills must be added via the app rather than the device, often negating the benefits of a VUI and breaking the conversational flow (not to mention excluding those who can’t/won’t use a smartphone). This makes the process feel clumsy and disjointed at best, completely isolating at worst. Even once a skill is installed, no skill visibility and a restricted time frame for interaction result in a lack of confidence and anxiety; can it do what I want? How do I talk to it? Has it heard me? So, how do you build that connection and trust?

For Susan, it meant stripping away the unnecessary and presenting a curated selection of core functionality. By personalizing the content to the unique behaviors and requirements, we presented much-needed clarity and a more meaningful experience. Susan wanted to perform key tasks: answer the phone, make a call, change the TV channel, play music, and so on. By getting to understand her and her needs, we created an assistant that always felt relevant and useful. This was quite a manual process, but there is a huge opportunity for machine learning and AI here. If every voice assistant could offer an element of personalization, it could make the experience feel more relevant for everyone.

As we were designing for one individual, we could easily tailor the physical elements of the product for Susan. This meant designing — then 3D printing — a light diffuser in the shape of an owl (her favorite animal and something with a significant meaning to her). The owl acted as a visual manifestation of the technology and gave her something to talk to and project towards. It was her guide that gave her access to those skills she wanted, such as listening to music. As it was personal to her, it made the potentially alien, intimidating technology feel much more approachable and familiar.


Humanizing technology helps make it more accessible: Susan’s personalized owl glows in response to her voice, letting her know she is being heard and understood.


Humanizing technology helps make it more accessible: Susan’s personalized owl glows in response to her voice, letting her know she is being heard and understood. (Large preview)

Although a fully custom 3D printed housing isn’t an option for every VUI project, there is an opportunity to create a more relevant device for people to communicate with, especially if their needs or usage of home assistants is quite specific. For example, you might talk to a voice-enabled light about your home lighting and a fridge about your groceries.

2. Think About Audio Affordances

Currently, the user does all the heavy lifting. With an obscured mental model and no hand-holding from the tech, we’re forced to imagine our desired endpoint and work backwards through the necessary commands. The simplest tasks aside (set a timer for 5 minutes, play Abba on Spotify, etc.), that’s incredibly hard to do, especially if you suffer from ‘foggy moments’ something that Susan explained to us — difficulty in finding the right words.

When Apple famously used skeuomorphic visual elements for their early iPhone apps, the user gained valuable, familiar reference points which afforded its use and method of interaction. Only once the mental model became more established did they have the freedom to move away from this literal representation, into their current flat UI.

When designing our VUI, we decided to lean on the well-established menu system seen throughout digital and web navigation. It’s a familiar tool which demands less cognitive processing from the user and allowed us to incorporate methods of way-finding that didn’t result in starting from the beginning if things went wrong.

As an example, Susan found verbalizing what she wanted, in the time frame offered by current digital assistants, a stressful and often unpleasant experience; often compounded by an error message from the device at the end of it. Rather than expecting her to give an explicit command such as “Alexa, play Abba from my Spotify playlist,” we decided to create a guided menu tool that could help her start slowly and get incrementally more specific about what she wanted Alexa to do.

Susan’s owl now prompts her with a curated list of options such as, “Play Music” or “Watch Something.” If she chooses music, it gets more specific as she progresses through each decision gate, to uncover the genre she feels like listening to; in the case of Abba, she would select “60s music.” This enables Susan to navigate to her desired outcome much more easily, and at a pace that suits her. All the while, the owl was glowing and responding to her voice, letting her know she was being heard and understood.


Susan’s voice assistant gives her back some of the independence she lost to her condition, from empowering her to making a phone call to family, or simply listening to music.


Susan’s voice assistant gives her back some of the independence she lost to her condition, from empowering her to making a phone call to family, or simply listening to music. (Large preview)

3. There’s More To VUIs Than Voice

The non-lexical components of verbal communication impart a great deal of meaning to a conversation. Some can be replicated by the synthesized voice (intonation, pitch, and speed of speaking, hesitation noises, to name a few), but many can’t (such as gesture and facial expression). The tangible elements of the product need to replace these traditional, visual cues for the interaction for it to feel even slightly natural. But there’s more to it than that.

Firstly, when someone interacts with a product designed to replicate human behaviors, the visual components are interpreted by the user’s preconceived notions of the world (both inherent and learned) and affect their emotional responses. If something looks imposing and cold, you’re much less likely to initiate a conversation than with something that looks cute and cuddly.

In our case, as the technology was so foreign to the user, we needed to make it feel as familiar and inviting as possible — an owl. In doing so, we hoped to remove the feelings of anxiety and frustration we had experienced with other products. We also amplified the visual side of it — there is one color for an idle state — a gentle glow, almost like breathing, but when Susan says the wake words the light changes to awake and listening.

You can go further. Apple, for example, has a full-color display on their Homepod which affords a higher level of nuance to their interaction and visualization. Adding a visual experience might sound counterintuitive, but visualizations can be very helpful for the user.

Conclusion

Although applied to an individual use-case, these top-level learnings can help any project hoping to utilize the inherent benefits voice affords. Personalizing the content (where possible) provides much-needed clarity and a logical, relatable navigation system reduces cognitive load. Finally, don’t underestimate the importance of the visual components; when done well, they not only deliver fundamental conversation cues, they set the tone for the whole interaction.

For those looking to experiment with voice, Amazon now showcases tens of thousands of skills from companies like Starbucks and Uber, as well as those created by other innovative designers and developers. The Alexa Skills Kit (ASK) is a collection of self-service APIs, tools, documentation, and code samples that make it easy for you to add skills to Alexa, and start creating your own solutions. Wondering if voice even makes sense? Here’s some considerations before you get started.

Smashing Editorial
(ra, il)


See more here: 

Designing The Invisible: 3 Things I Learned Designing For Voice

Thumbnail

The Most Effective Ecommerce Lead Generation Tips and Strategies

ecommerce-lead-generation

I have some bad news for you. It might hurt. Everything you’ve read about lead generation strategies might not apply to your business. Why? Because ecommerce lead generation is different. If you run a business outside the ecommerce family, feel free to check out another Crazy Egg article that applies to your company. For those of you in the ecommerce market, though, we need to set a few things straight. I’m going to share with you my best tips for effective ecommerce lead generation, and you might notice that they’re not the same as the tactics you might use for,…

The post The Most Effective Ecommerce Lead Generation Tips and Strategies appeared first on The Daily Egg.

Follow this link: 

The Most Effective Ecommerce Lead Generation Tips and Strategies

Thumbnail

19 Call-to-Action Phrases That Will Convert Your Users

call-to-action-phrases

What happens when nobody clicks on your call-to-action phrases and buttons? You don’t get any leads. Nor do you generate any revenue. That’s the opposite of the point, right? Which is why I tell business owners and marketers to take the time to refine their CTAs. A poorly-written CTA negates all the hard work you do for the rest of your marketing campaign. Someone who visits your website might be with you up until that point, then decide to bail on the conversion. So, how do you write call-to-action phrases that convert? What is the Psychology Behind CTA Phrases? From…

The post 19 Call-to-Action Phrases That Will Convert Your Users appeared first on The Daily Egg.

See the original article here:  

19 Call-to-Action Phrases That Will Convert Your Users

Thumbnail

Everything You Need To Know About Alignment In Flexbox




Everything You Need To Know About Alignment In Flexbox

Rachel Andrew



In the first article of this series, I explained what happens when you declare display: flex on an element. This time we will take a look at the alignment properties, and how these work with Flexbox. If you have ever been confused about when to align and when to justify, I hope this article will make things clearer!

History Of Flexbox Alignment

For the entire history of CSS Layout, being able to properly align things on both axes seemed like it might truly be the hardest problem in web design. So the ability to properly align items and groups of items was for many of us the most exciting thing about Flexbox when it first started to show up in browsers. Alignment became as simple as two lines of CSS:

See the Pen Smashing Flexbox Series 2: center an item by Rachel Andrew (@rachelandrew) on CodePen.

The alignment properties that you might think of as the flexbox alignment properties are now fully defined in the Box Alignment Specification. This specification details how alignment works across the various layout contexts. This means that we can use the same alignment properties in CSS Grid as we use in Flexbox — and in future in other layout contexts, too. Therefore, any new alignment capability for flexbox will be detailed in the Box Alignment specification and not in a future level of Flexbox.

The Properties

Many people tell me that they struggle to remember whether to use properties which start with align- or those which start with justify- in flexbox. The thing to remember is that:

  • justify- performs main axis alignment. Alignment in the same direction as your flex-direction
  • align- performs cross-axis alignment. Alignment across the direction defined by flex-direction.

Thinking in terms of main axis and cross axis, rather than horizontal and vertical really helps here. It doesn’t matter which way the axis is physically.

Main Axis Alignment With justify-content

We will start with the main axis alignment. On the main axis, we align using the justify-content property. This property deals with all of our flex items as a group, and controls how space is distributed between them.

The initial value of justify-content is flex-start. This is why, when you declare display: flex all your flex items line up against the start of the flex line. If you have a flex-direction of row and are in a left to right language such as English, then the items will start on the left.


The items are all lined up in a row starting on the left


The items line up to the start (Large preview)

Note that the justify-content property can only do something if there is spare space to distribute. Therefore if you have a set of flex items which take up all of the space on the main axis, using justify-content will not change anything.


The container is filled with the items


There is no space to distribute (Large preview)

If we give justify-content a value of flex-end then all of the items will move to the end of the line. The spare space is now placed at the beginning.


The items are displayed in a row starting at the end of the container — on the right


The items line up at the end (Large preview)

We can do other things with that space. We could ask for it to be distributed between our flex items, by using justify-content: space-between. In this case, the first and last item will be flush with the ends of the container and all of the space shared equally between the items.


Items lined up left and right with equal space between them


The spare space is shared out between the items (Large preview)

We can ask that the space to be distributed around our flex items, using justify-content: space-around. In this case, the available space is shared out and placed on each side of the item.


Items spaced out with even amounts of space on each side


The items have space either side of them (Large preview)

A newer value of justify-content can be found in the Box Alignment specification; it doesn’t appear in the Flexbox spec. This value is space-evenly. In this case, the items will be evenly distributed in the container, and the extra space will be shared out between and either side of the items.


Items with equal amounts of space between and on each end


The items are spaced evenly (Large preview)

You can play with all of the values in the demo:

See the Pen Smashing Flexbox Series 2: justify-content with flex-direction: row by Rachel Andrew (@rachelandrew) on CodePen.

These values work in the same way if your flex-direction is column. You may not have extra space to distribute in a column however unless you add a height or block-size to the flex container as in this next demo.

See the Pen Smashing Flexbox Series 2: justify-content with flex-direction: column by Rachel Andrew (@rachelandrew) on CodePen.

Cross Axis Alignment with align-content

If you have added flex-wrap: wrap to your flex container, and have multiple flex lines then you can use align-content to align your flex lines on the cross axis. However, this will require that you have additional space on the cross axis. In the below demo, my cross axis is running in the block direction as a column, and I have set the height of the flex container to 60vh. As this is more than is needed to display my flex items I have spare space vertically in the container.

I can then use align-content with any of the values:

See the Pen Smashing Flexbox Series 2: align-content with flex-direction: row by Rachel Andrew (@rachelandrew) on CodePen.

If my flex-direction were column then align-content would work as in the following example.

See the Pen Smashing Flexbox Series 2: align-content with flex-direction: column by Rachel Andrew (@rachelandrew) on CodePen.

As with justify-content, we are working with the lines as a group and distributing the spare space.

The place-content Shorthand

In the Box Alignment, we find the shorthand place-content; using this property means you can set justify-content and align-content at once. The first value is for align-content, the second for justify-content. If you only set one value then both values are set to that value, therefore:

.container 
    place-content: space-between stretch;

Is the same as:

.container 
    align-content: space-between; 
    justify-content: stretch;

If we used:

.container 
    place-content: space-between;

This would be the same as:

.container 
    align-content: space-between; 
    justify-content: space-between;

Cross Axis Alignment With align-items

We now know that we can align our set of flex items or our flex lines as a group. However, there is another way we might wish to align our items and that is to align items in relationship to each other on the cross axis. Your flex container has a height. That height might be defined by the height of the tallest item as in this image.


The container height is tall enough to contain the items, the third item has more content


The container height is defined by the third item (Large preview)

It might instead be defined by adding a height to the flex container:


The container height is taller than needed to display the items


THe height is defined by a size on the flex container (Large preview)

The reason that flex items appear to stretch to the size of the tallest item is that the initial value of align-items is stretch. The items stretch on the cross access to become the size of the flex container in that direction.

Note that where align-items is concerned, if you have a multi-line flex container, each line acts like a new flex container. The tallest item in that line would define the size of all items in that line.

In addition to the initial value of stretch, you can give align-items a value of flex-start, in which case they align to the start of the container and no longer stretch to the height.


The items are aligned to the start


The items aligned to the start of the cross axis (Large preview)

The value flex-end moves them to the end of the container on the cross axis.


Items aligned to the end of the cross axis


The items aligned to the end of the cross axis (Large preview)

If you use a value of center the items all centre against each other:


The items are centered


Centering the items on the cross axis (Large preview)

We can also do baseline alignment. This ensures that the baselines of text line up, as opposed to aligning the boxes around the content.


The items are aligned so their baselines match


Aligning the baselines (Large preview)

You can try these values out in the demo:

See the Pen Smashing Flexbox Series 2: align-items by Rachel Andrew (@rachelandrew) on CodePen.

Individual Alignment With align-self

The align-items property means that you can set the alignment of all of the items at once. What this really does is set all of the align-self values on the individual flex items as a group. You can also use the align-self property on any individual flex item to align it inside the flex line and against the other flex items.

In the following example, I have used align-items on the container to set the alignment for the group to center, but also used align-self on the first and last items to change their alignment value.

See the Pen Smashing Flexbox Series 2: align-self by Rachel Andrew (@rachelandrew) on CodePen.

Why Is There No justify-self?

A common question is why it is not possible to align one item or a group of the items on the main axis. Why is there no -self property for main axis alignment in Flexbox? If you think about justify-content and align-content as being about space distribution, the reason for their being no self-alignment becomes more obvious. We are dealing with the flex items as a group, and distributing available space in some way — either at the start or end of the group or between the items.

If might be also helpful to think about how justify-content and align-content work in CSS Grid Layout. In Grid, these properties are used to distribute spare space in the grid container between grid tracks. Once again, we take the tracks as a group, and these properties give us a way to distribute any extra space between them. As we are acting on a group in both Grid and Flexbox, we can’t target an item on its own and do something different with it. However, there is a way to achieve the kind of layout that you are asking for when you ask for a self property on the main axis, and that is to use auto margins.

Using Auto Margins On The Main Axis

If you have ever centered a block in CSS (such as the wrapper for your main page content by setting a margin left and right of auto), then you already have some experience of how auto margins behave. A margin set to auto will try to become as big as it can in the direction it has been set in. In the case of using margins to center a block, we set the left and right both to auto; they each try and take up as much space as possible and so push our block into the center.

Auto margins work very nicely in Flexbox to align single items or groups of items on the main axis. In the next example, I am achieving a common design pattern. I have a navigation bar using Flexbox, the items are displayed as a row and are using the initial value of justify-content: start. I would like the final item to be displayed separated from the others at the end of the flex line — assuming there is enough space on the line to do so.

I target that item and give it a margin-left of auto. This then means that the margin tries to get as much space as possible to the left of the item, which means the item gets pushed all the way over to the right.

See the Pen Smashing Flexbox Series 2: alignment with auto margins by Rachel Andrew (@rachelandrew) on CodePen.

If you use auto margins on the main axis then justify-content will cease to have any effect, as the auto margins will have taken up all of the space that would otherwise be assigned using justify-content.

Fallback Alignment

Each alignment method details a fallback alignment, this is what will happen if the alignment you have requested can’t be achieved. For example, if you only have one item in a flex container and ask for justify-content: space-between, what should happen? The answer is that the fallback alignment of flex-start is used and your single item will align to the start of the flex container. In the case of justify-content: space-around, a fallback alignment of center is used.

In the current specification you can’t change what the fallback alignment is, so if you would prefer that the fallback for space-between was center rather than flex-start, there isn’t a way to do that. There is a note in the spec which says that future levels may enable this.

Safe And Unsafe Alignment

A more recent addition to the Box Alignment specification is the concept of safe and unsafe alignment using the safe and unsafe keywords.

With the following code, the final item is too wide for the container and with unsafe alignment and the flex container on the left-hand side of the page, the item becomes cut off as the overflow is outside the page boundary.

.container   
    display: flex;
    flex-direction: column;
    width: 100px;
    align-items: unsafe center;


.item:last-child 
    width: 200px;

The overflowing item is centered and partly cut off


Unsafe alignment will give you the alignment you asked for but may cause data loss (Large preview)

A safe alignment would prevent the data loss occurring, by relocating the overflow to the other side.

.container   
    display: flex;
    flex-direction: column;
    width: 100px;
    align-items: safe center;


.item:last-child 
    width: 200px;

The overflowing item overflows to the right


Safe alignment tries to prevent data loss (Large preview)

These keywords have limited browser support right now, however, they demonstrate the additional control being brought to Flexbox via the Box Alignment specification.

See the Pen Smashing Flexbox Series 2: safe or unsafe alignment by Rachel Andrew (@rachelandrew) on CodePen.

In Summary

The alignment properties started as a list in Flexbox, but are now in their own specification and apply to other layout contexts. A few key facts will help you to remember how to use them in Flexbox:

  • justify- the main axis and align- the cross axis;
  • To use align-content and justify-content you need spare space to play with;
  • The align-content and justify-content properties deal with the items as a group, sharing out space. Therefore, you can’t target an individual item and so there is no -self alignment for these properties;
  • If you do want to align one item, or split a group on the main axis, use auto margins to do so;
  • The align-items property sets all of the align-self values as a group. Use align-self on the flex child to set the value for an individual item.
Smashing Editorial
(il)


See original:

Everything You Need To Know About Alignment In Flexbox