Estimote Mirror Documentation

Hey Estimote People,

I have 6 of your mirrors, really like the hardware so far, its the perfect fit for our application.
After some brief tinkering and trying your simple examples on http://developer.estimote.com/mirror/templates-with-beacon-triggers and documentation on http://developer.estimote.com/mirror/javascript-api-for-templates

The nearable samples yield no results I’ve tried with Stickers, Location and Proximity beacons and there are no scan results. I’m also interested in the debug path, as i see console.log() functions in your samples and a msg_logging flag on your mirror object but I don’t see a path for attaining the logging data.

Do you have any details on how to debug code running on the mirror as well as why the beacon trigger samples are not detecting the beacons?

Thanks!

Mhm, can you double-check if your Proximity/Location beacons have Estimote Telemetry enabled? And for Stickers, they should be set to Nearable packet/broadcasting.

As for debugging, right now it is in fact quite inconvenient, something that we’re well aware of that needs fixing. We have some ideas and even partial implementations … but for now, I’ll have to suggest just showing any debug messages on the TV’s screen. Here’s a little helper function I made for myself when I was working on some Mirror templates:

const debugPopup = (...messages) => {
    const message = messages.reduce((acc, val) => {
        let str = typeof val === 'string' ? val : JSON.stringify(val);
        return `${acc} ${str}`;
    }, '');

    let debugLog = document.querySelector('#__built-in-views-debug-log');
    if (debugLog === null) {
        debugLog = document.createElement('div');
        debugLog.id = '__built-in-views-debug-log';
        document.body.appendChild(debugLog);
    }

    const debugLogEntry = document.createElement('p');
    debugLogEntry.innerHTML = `=> ${message}`;
    debugLog.appendChild(debugLogEntry);
    setTimeout(() => {
        debugLog.removeChild(debugLogEntry);
    }, 20 * 1000);
};

window.onerror = (messageOrEvent) => {
    debugPopup('onerror', messageOrEvent);
};

There is a built-in test template called estimote/scanner. Switch Mirror to it (using SDK or call mirror.selectTemplate('estimote/scanner') from template code) and you should see a list of devices. If there are no devices on the list (and you are sure that there are beacons near by) this might mean that your unit is damaged. If that template shows results this might mean that you have an error in JavaScript that prevents scanner to start.

1 Like

Thanks @heypiotr and @pober The debug view is really nice to have.
I had a look at the HTML and your sample doesn’t include a height which seems to prevent the text from being displayed.

Everything looks good now, thanks for your suggestions.

I have noticed on my video testing that I get diagonal screen tearing on 480p video, is there anything that can be done to improve the video rendering?

Hi there, I’m having trouble getting my own template for scanning nearby devices working

When I run mirror.selectTemplate('estimote/scanner'); the mirror seems to pick up quite a few devices, but when I use the Scanner API in my own template it’s returning nothing.

This is the code I am using:

debugPopup('init mirror...');
mirror.init();

debugPopup('mirror start scanning...');
mirror.listen(Mirror.Events.SCAN, {
  onscan: function(event){
    debugLog('scanning...');

    for (const device of event.devices) {
      debugLog(device.id);
    }
  }
});

As you can see, I’m using the suggested debugPopup from above. It seems to be working fine, but nothing is being logged from inside the onscan listener.

You are calling debugLog instead of debugPopup. debugLog is an internal variable (declared using let) of debugPopup function and won’t be accessible from onscan callback.
Try this code, it should work:

<html>
<head>
    <script>
        const debugPopup = (...messages) => {
            const message = messages.reduce((acc, val) => {
                let str = typeof val === 'string' ? val : JSON.stringify(val);
                return `${acc} ${str}`;
            }, '');
            let debugLog = document.querySelector('#__built-in-views-debug-log');
            if (debugLog === null) {
                debugLog = document.createElement('div');
                debugLog.id = '__built-in-views-debug-log';
                document.body.appendChild(debugLog);
            }
            const debugLogEntry = document.createElement('p');
            debugLogEntry.innerHTML = `=> ${message}`;
            debugLog.appendChild(debugLogEntry);
            setTimeout(() => {
                debugLog.removeChild(debugLogEntry);
            }, 20 * 1000);
        };
        window.onerror = (messageOrEvent) => {
            debugPopup('onerror', messageOrEvent);
        };
    </script>
</head>
<body>
    <script>
        debugPopup('init mirror...');
        mirror.init();
        debugPopup('mirror start scanning...');
        mirror.listen(Mirror.Events.SCAN, {
            onscan: function(event) {
                debugPopup('scanning...');
                for (const device of event.devices) {
                    debugPopup(device.id);
                }
            }
        });
    </script>
</body>
</html>
1 Like

@pober, thanks for picking that up! I didn’t even realise I was calling the wrong function :sweat_smile:

I have the debugPopup code in my template and was calling it everywhere else except inside the onscan callback.

1 Like

Hi,
I encountered a similar problem with my beacons.
I verified and my beacon have telemetry enabled.
My debug method is debugPopup but my mirror does not enter in “onscan” :confused:
However, when I launch “estimote/scanner” template my beacons are found.

here is my code:

debugPopup("Mirror Init");
mirror.init();
mirror.selectTemplate(null);
mirror.setScanFilter({
    types: ["telemetry", "nearable"],
    ids: [BEACON_ID_1, BEACON_ID_2]
});

mirror.listen(Mirror.Events.SCAN, {
    onscan: function (event) {
        debugPopup("Scanning");
        for (const device of event.devices) {
            debugPopup(device.id);
            if (device.motion == false) {
                continue;
            }
        }

        debugPopup("Motion");

        if (device.id == BEACON_ID_1) {
            debugPopup("Pink");
        }
        if (device.id == BEACON_ID_2) {
            debugPopup("Yellow");
        }
    }
});

I would remove the line mirror.selectTemplate(null);. It will make Mirror switch to default template immediately when template is loaded. If this template is the default template then nothing will happen (no need to switch default to default). But in any other case selecting this template will end up with landing on default.

I assume that scanning code from my previous post does not work too and debugPopup displays at least one message?

Described behavior is strange because even if scan filters were bad (did not match anything) you still should get onscan callback (with empty devices). On the other hand if scanned packets are not delivered (for example Bluetooth stack is not working) then estimote/scanner template should show empty list.

Other thing I noticed is that in lines:

        if (device.id == BEACON_ID_1) {
            debugPopup("Pink");
        }
        if (device.id == BEACON_ID_2) {
            debugPopup("Yellow");
        }

You are calling object device that was not declared there. device exists only in for loop. It looks like closing brace } of for loop should be moved before closing brace of onscan function:

  mirror.listen(Mirror.Events.SCAN, {
            onscan: function(event) {
                debugPopup("Scanning");
                for (const device of event.devices) {
                    debugPopup(device.id);
                    if (device.motion == false) {
                        continue;
                    }
                    debugPopup("Motion");
                    if (device.id == BEACON_ID_1) {
                        debugPopup("Pink");
                    }
                    if (device.id == BEACON_ID_2) {
                        debugPopup("Yellow");
                    }
                }
            }
        });

Anyway I tested code on several Mirrors (after removing mirror.selectTemplate(null);)
and it worked without problems. There might me something wrong in the template code that was not posted here and it might be affecting scanning.

BTW. Identifiers are case sensitive. Make sure they are lowercase and without trailing/leading white spaces.

What firmware version your Mirror is running (you can check that in cloud console)?

Thanks for your answer, the problem was the selection of the template :slight_smile:
My mirror is running 1.0.9 firmware version.

btw, how can I update firmware on mirror ? because I can’t see the same thing as beacons neither on mobile app, nor on cloud :confused:

When WiFi is configured and working Mirror will update itself automatically. You will see a message that a new firmware is available and you need to reboot the device to install it.

Hi,

I’m struggling with my first Estimote Mirror template - I’m using following code:

<html>
<head>
    <script>
        const debugPopup = (...messages) => {
            const message = messages.reduce((acc, val) => {
                let str = typeof val === 'string' ? val : JSON.stringify(val);
                return `${acc} ${str}`;
            }, '');
            let debugLog = document.querySelector('#__built-in-views-debug-log');
            if (debugLog === null) {
                debugLog = document.createElement('div');
                debugLog.id = '__built-in-views-debug-log';
                document.body.appendChild(debugLog);
            }
            const debugLogEntry = document.createElement('p');
            debugLogEntry.innerHTML = `=> ${message}`;
            debugLog.appendChild(debugLogEntry);
            setTimeout(() => {
                debugLog.removeChild(debugLogEntry);
            }, 20 * 1000);
        };
        window.onerror = (messageOrEvent) => {
            debugPopup('onerror', messageOrEvent);
        };
    </script>
</head>
<body>
    <script>
	const BEACON_ID_1 = "here goes sticker ID 16 digits";
	const BEACON_ID_2 = "here goes another sticker ID 16 digits";
	
       debugPopup("Mirror Init");
		mirror.init();
		mirror.setScanFilter({
			types: ["telemetry", "nearable"],
			ids: [BEACON_ID_1, BEACON_ID_2]
		});
		
		  mirror.listen(Mirror.Events.SCAN, {
            onscan: function(event) {
                debugPopup("Scanning");
                for (const device of event.devices) {
                    debugPopup(device.id);
                    if (device.motion == false) {
                        continue;
                    }
                    debugPopup("Motion");
                    if (device.id == BEACON_ID_1) {
                        debugPopup("Pink");
                    }
                    if (device.id == BEACON_ID_2) {
                        debugPopup("Yellow");
                    }
                }
            }
        });
    </script>
</body>
</html>

Unfortunately, seems that the code cannot start onscan function (got only Mirror Init message on the screen). Any clues what I’m doing wrong? Estimote Mirror software version 1.09. Template estimote/scanner works and show beacons and bluetooth devices in the neighbourhood.

Thanks in advance!

I copy-pasted your code into Mirror with firmware 1.0.9 and it shows Scanning message all over the screen. Of course it does not return any devices because IDs in filters are not set properly.
Here are some steps that might help you:

  1. Update your firmware to latest version (should be 1.0.15 right now)
  2. Use built-in debugPopup and redirectConsoleToPopup. See API documentation
  3. Check your code for typos or copy paste code from forum. Try to comment out filters setup.

I investigated it a little bit further and this is what I come up with:

  1. It happens only on device startup when the first template is displayed (default one).
  2. It has been fixed in 1.0.10
  3. This quick and simple workaround may help (you may try to adjust timeout):
   setTimeout(mirror.initSocket, 2000)

Place it after mirror.init()