Inqling - A Test Mu...
 
Notifications
Clear all

Inqling - A Test Mule

35 Posts
7 Users
12 Likes
1,173 Views
Inq
 Inq
(@inq)
Noble Member
Joined: 8 months ago
Posts: 959
Topic starter  

Beta Client Side HTML Page

Index.html

This is the HTML page representing the dashboard and joystick of Inqling.  90% of this page is to configure the dial gauges use by the JavaScript library gauge.min.js (Attached)

<!DOCTYPE html>
<html>
<head>
  <title>Inqling</title>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <link rel='stylesheet' type='text/css' href='InqStyle.css'>
  <script src='InqPortal.js'></script>
  <script src='gauge.min.js'></script>
  <script src='Inqling.js'></script>
  
  <style>
	.noscrl{ overflow:hidden; }
    .abs{ position:absolute; }
    #joy{ position:absolute; left:1em; background-color:white; 
	  border-radius: 1em;}    
  </style>  
  
</head>
<body class='noscrl' 
  <div id='dash'>
    <canvas id='gas' onclick='fullScreen();'
        data-type='radial-gauge'
        data-units='Run Time %'
        data-title='false'
        data-value='50'
        data-animate-on-init='false'
        data-animated-value='false'
        data-min-value='0'
        data-max-value='100'
        data-major-ticks='0,10,20,30,40,50,60,70,80,90,100'
        data-minor-ticks='2'
        data-stroke-ticks='false'
        data-highlights='[
            { "from": 0, "to": 10, "color": "rgba(170,0,0,0.8)" },
            { "from": 10, "to": 20, "color": "rgba(170,170,0,0.8)" },
            { "from": 20, "to": 100, "color": "rgba(0,170,0,0.8)" }
        ]'
        data-color-plate='transparent'
        data-color-major-ticks='#f5f5f5'
        data-color-minor-ticks='#ddd'
        data-color-title='#fff'
        data-color-units='#ccc'
        data-color-numbers='#eee'
        data-color-needle-start='#f00'
        data-color-needle-end='#f00'
        data-value-box='true'
        data-animation-rule='bounce'
        data-animation-duration='500'
		data-border-shadow-width="0"
		data-borders="false">		
    </canvas>
	<canvas id='lSpeed' class='abs'
		data-type="radial-gauge"
		data-units="Throttle %"
		data-min-value="-100"
		data-start-angle="10"
		data-ticks-angle="160"
		data-value-box="false"
		data-max-value="100"
		data-major-ticks="-100,-80,-60,-40,-20,0,20,40,60,80,100"
		data-minor-ticks="2"
		data-stroke-ticks="false"
		data-highlights='[
			{"from": -100, "to": -90, "color": "rgba(170,0,0,0.8)"},
			{"from": -90, "to": 90, "color": "rgba(0,170,0,0.8)"},
			{"from": 90, "to": 100, "color": "rgba(170,0,0,0.8)"}
		]'
		data-color-plate="transparent"
        data-color-major-ticks='#f5f5f5'
        data-color-minor-ticks='#ddd'
        data-color-title='#fff'
        data-color-units='#ccc'
        data-color-numbers='#eee'
        data-color-needle-start='#f00'
        data-color-needle-end='#f00'

		data-border-shadow-width="0"
		data-borders="false"
		data-needle-type="arrow"
		data-needle-width="4"
		data-needle-circle-size="7"
		data-needle-circle-outer="true"
		data-needle-circle-inner="false"
        data-animation="false">
	</canvas>
	<canvas id='rSpeed' class='abs' onclick='fullScreen();'
		data-type="radial-gauge"
		data-units="Throttle %"
		data-min-value="-100"
		data-start-angle="190"
		data-ticks-angle="160"
		data-value-box="false"
		data-max-value="100"
		data-major-ticks="100,80,60,40,20,0,-20,-40,-60,-80,-100"
		data-minor-ticks="2"
		data-stroke-ticks="false"
		data-highlights='[
			{"from": -100, "to": -90, "color": "rgba(170,0,0,0.8)"},
			{"from": -90, "to": 90, "color": "rgba(0,170,0,0.8)"},
			{"from": 90, "to": 100, "color": "rgba(170,0,0,0.8)"}
		]'
		data-color-plate="transparent"
        data-color-major-ticks='#f5f5f5'
        data-color-minor-ticks='#ddd'
        data-color-title='#fff'
        data-color-units='#ccc'
        data-color-numbers='#eee'
        data-color-needle-start='#f00'
        data-color-needle-end='#f00'

		data-border-shadow-width="0"
		data-borders="false"
		data-needle-type="arrow"
		data-needle-width="4"
		data-needle-circle-size="7"
		data-needle-circle-outer="true"
		data-needle-circle-inner="false"
        data-animation="false">
	</canvas>  
  </div>
  <canvas id='joy'></canvas>    
</body>
</html>

 

3rd Party library by:  Copyright (c) 2016 Mykhailo Stadnyk <mikhus@gmail.com>

 

3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, Access Point Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide


   
ReplyQuote
Inq
 Inq
(@inq)
Noble Member
Joined: 8 months ago
Posts: 959
Topic starter  

Beta Inqling Client Side JavaScript File

Inqling.js

This is the client side file that allows the user to use the "Joy Stick" on the browser GUI as well as giving feedback on the current values of the Inqling robot.  This is used in conjunction with the Index.html file to display the Inqling GUI.

image
var em;     // Size of a "character".  Same as em Html unit.
var joy;    // Joystick white cavas.
var ctx;    // Context for joystick

// Since multiple browser clients can be simultaneously hooked up
// to the server, we do the following logic.
// * mouse/finger movement on the joystick area is considered commands to
//      set the relative speeds of the two Inqling motors.
// * Commands are sent on MouseDown and MouseUp (MouseUp return joystick to
//      neutral / all-stop position).
// * Commands are also sent 60 times a second if they have changed since the
//      last one sent.
// * Behavior is problematic if two browser are sending commands.  This case
//      is not handled!!!
// * The server reports back the current motor speeds.  The speed gauges and
//      joystick DOT position are based on the server value... not the finger
//      location.
var pos;    // Position of joystick
var sent;   // Last speed sent by this instance of the client.
var dot;    // Positons of dot which is from feedback from server.
var zero;

onConnected = function()
{
    // onConnected - is InqPortal event once the page is loaded AND has
    // connected to the InqPortal server on the ESP8266.    
    
    em = parseFloat(getComputedStyle(document.querySelector('body'))
        ['font-size']);        
    joy = $('joy');
    ctx = joy.getContext('2d');
    
    //joy.addEventListener('touchstart', mouseDown, false);
    //joy.addEventListener('touchmove', mouseMove, false);
    //joy.addEventListener('touchend', mouseUp, false);
    joy.onpointerdown = mouseDown;
    joy.onpointerup = mouseUp;
   
    resize();

    pos = { X: joy.width / 2, Y: joy.height / 2 };
    dot = { X: pos.X, Y: pos.Y };
    zero = { X: pos.X, Y: pos.Y };
    sent = { X:0, Y:0, LS:0, RS:0 };
    setInterval(SendSpeeds, 1000 / 60);
};

onModifyResult = function(p, v)
{
    // onModifyResult - is InqPortal event allowing data coming from
    // the InqPortal ESP8266 server to be inspected, used, modified before
    // showing on the browser client.
    switch (p)
    {
        case 'X':
            let x = joy.width / 2;
            dot.X = x + v / 100 * x;
            break;
            
        case 'Y':
            let y = joy.height / 2;
            dot.Y = y - v / 100 * y;            
            break;
            
        case 'LS':
            document.gauges.get("lSpeed").value = v;
            break;
            
        case 'RS':
            document.gauges.get("rSpeed").value = -v;
            break;    
        
        case 'V':
            // Combined.xlsx - Excel generated trendline equations from drain 
            // down tests.  Time = f(voltage)
            // One equation could not adequately approximate the curve.  
            // Did a piece-wise function.  Below the 3.519V mark the batteries
            // drained at a far higher rate.  By using these functions, we can
            // do a pretty-good time estimator of percentage of time left.
            // The 3.519V transition occurs when 20% of the time is left.
            let f = v < 3.519 ?
                -0.1663 * v * v + 0.798 * v + 0.041 :
                -2.0519 * v * v * v + 24.898 * v * v - 101.49 * v + 139.03;
            // Convert to time left in percentage.
            document.gauges.get("gas").value = 
                Math.min(100, Math.max(0, (1 - f) * 100));
            break;
    }
    return v;   // Any unmodifed variables need to be returned also.
};

function plot() 
{
    // Draw over the whole canvas to create the trail effect
    ctx.fillStyle = 'rgba(255, 255, 255, .05)';
    ctx.fillRect(0, 0, joy.width, joy.height);

    ctx.strokeStyle = "#005500";

    ctx.beginPath();
    ctx.lineWidth = 3;
    ctx.moveTo(joy.width / 2, 0);
    ctx.lineTo(joy.width / 2, joy.height);
    ctx.moveTo(0, joy.height / 2);
    ctx.lineTo(joy.width, joy.height / 2);
    ctx.stroke();
    
    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.moveTo(0, 0);
    ctx.lineTo(joy.width, joy.height);
    ctx.moveTo(joy.width, 0);
    ctx.lineTo(0, joy.height);
    ctx.stroke();
    
    // Draw dot.
    ctx.beginPath();
    ctx.fillStyle = '#ff0000';
    ctx.arc(dot.X, dot.Y, em, 0, Math.PI * 2, true);
    ctx.fill();
};

function mouseDown(e)
{
    joy.setPointerCapture(e.pointerId);
    joy.onpointermove = mouseMove;
    getPos(e);
    SendSpeeds();
};	

function mouseMove(e)
{
    getPos(e);      
};

function mouseUp(e)
{
    joy.onpointermove = null;
    joy.releasePointerCapture(e.pointerId);
    ctx.fillStyle = 'rgba(255, 255, 255, 1)';
    ctx.fillRect(0, 0, joy.width, joy.height);
    pos.X = joy.width / 2;
    pos.Y = joy.height / 2;
    SendSpeeds();
};		

var m = 0;

function getPos(e)
{
    if (e.targetTouches)
    {
        let touch = e.targetTouches[0];
        pos.X = touch.clientX - joy.offsetLeft;
        pos.Y = touch.clientY - joy.offsetTop;
        e.preventDefault();		
    }
    else
    {
        pos.X = Math.max(0, Math.min(joy.width, e.offsetX));
        pos.Y = Math.max(0, Math.min(joy.height, e.offsetY));
    }
};
    
function SendSpeeds()
{
    plot();
    
    let x = joy.width / 2;
    let y = joy.height / 2;
    x = Math.round((pos.X - x) / x * 100);
    y = Math.round((y - pos.Y) / y * 100);
    let l = y + x;
    let r = y - x;
    let m = Math.max(Math.abs(l), Math.abs(r));

    if (m > 100)
    {
        l = Math.round(l / m * 100);
        r = Math.round(r / m * 100);
    }		
    if ((l != sent.LS) || (r != sent.RS))
    {
        sent.X = Number(x);
        sent.Y = Number(y);
        sent.LS = Number(l);
        sent.RS = Number(r);
        if (JSON.stringify(sent).includes(':null'))
            return;
        set(sent);
    }
};

function resize()
{		
    let d = $('dash').clientWidth / 2;
    let g = $('gas');
    g.setAttribute('data-width', d);
    g.setAttribute('data-height', d);		
    g = $('lSpeed');
    g.style.left = d + 'px';
    g.setAttribute('data-width', d);
    g.setAttribute('data-height', d);		
    g = $('rSpeed');
    g.style.left = d + 'px';
    g.setAttribute('data-width', d);
    g.setAttribute('data-height', d);
    
    if (joy)
    {
        joy.style.top = d + 'px';
        joy.width = window.innerWidth - 2 * em;
        joy.height = window.innerHeight - d - em;
    }
};

window.onresize = resize;

3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, Access Point Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide


   
ReplyQuote
Inq
 Inq
(@inq)
Noble Member
Joined: 8 months ago
Posts: 959
Topic starter  

And I just know you all have been pining away waiting for the Academy Award Winning video.  🤣 🤩 😘 

3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, Access Point Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide


   
robotBuilder and DaveE reacted
ReplyQuote
robotBuilder
(@robotbuilder)
Noble Member
Joined: 3 years ago
Posts: 1554
 

@inq

Thanks for sharing. Just book marked it as a how to do example.

 


   
ReplyQuote
Inq
 Inq
(@inq)
Noble Member
Joined: 8 months ago
Posts: 959
Topic starter  

@valerio just reminded me that I'd forgotten to supply the 3D Print files.  I didn't really think that anyone really wanted to make a Inqling, but for completeness sake, I should provide them.  Here is a zip file of everything: 

  • SketchUp CAD file (SKP)
  • STL Files (STL)
  • Client side code (HTML, JS, CSS)
  • Server side code (INO)

 

InqLing

Stay tuned - I think I see Inqling II in coming.

3 lines of code = InqPortal = Complete IoT, App, Web Server w/ GUI Admin Client, Access Point Manager, Drag & Drop File Manager, OTA, Performance Metrics, Web Socket Comms, Easy App API, All running on ESP8266...
Even usable on ESP-01S - Quickest Start Guide


   
ReplyQuote
Page 3 / 3