You are reading a single comment by @Hank and its replies. Click here to read the full conversation.
  • Thanks for the explanation!
    This is my test code:

    // ------- Settings file
    const SETTINGSFILE = "hworldclock.json";
    var secondsMode;
    var showSunInfo;
    var colorWhenDark;
    // ------- Settings file
    
    const big = g.getWidth()>200;
    // Font for primary time and date
    const primaryTimeFontSize = big?6:5;
    const primaryDateFontSize = big?3:2;
    require("Font5x9Numeric7Seg").add(Graphi­cs);
    require("FontTeletext10x18Ascii").add(Gr­aphics);
    
    // Font for single secondary time
    const secondaryTimeFontSize = 4; 
    const secondaryTimeZoneFontSize = 2;
    
    // Font / columns for multiple secondary times
    const secondaryRowColFontSize = 2;
    const xcol1 = 10;
    const xcol2 = g.getWidth() - xcol1;
    
    const font = "6x8";
    
    /* TODO: we could totally use 'Layout' here and
    avoid a whole bunch of hard-coded offsets */
    
    const xyCenter = g.getWidth() / 2;
    const xyCenterSeconds = xyCenter + (big ? 85 : 68);
    const yAmPm = xyCenter - (big ? 70 : 48);
    const yposTime = big ? 70 : 55;
    const yposTime2 = yposTime + (big ? 100 : 60);
    const yposDate = big ? 135 : 95;
    const yposWorld = big ? 170 : 120;
    
    const OFFSET_TIME_ZONE = 0;
    const OFFSET_HOURS = 1;
    
    var PosInterval = 0; 
    
    var offsets = require("Storage").readJSON("hworldclock­.settings.json") || [];
    
    //=======Sun
    setting = require("Storage").readJSON("setting.jso­n",1);
    E.setTimeZone(setting.timezone); // timezone = 1 for MEZ, = 2 for MESZ
    SunCalc = require("hsuncalc.js");
    const LOCATION_FILE = "mylocation.json";
    var rise = "read";
    var set	= "...";
    //var pos	 = {altitude: 20, azimuth: 135};
    //var noonpos = {altitude: 37, azimuth: 180};
    //=======Sun
    
    var ampm = "AM";
    
    // TESTING CODE
    // Used to test offset array values during development.
    // Uncomment to override secondary offsets value
    /*
    const mockOffsets = {
    	zeroOffsets: [],
    	oneOffset: [["UTC", 0]],
    	twoOffsets: [
    		["Tokyo", 9],
    		["UTC", 0],
    	],
    	 fourOffsets: [
    		["Tokyo", 9],
    		["UTC", 0],
    		["Denver", -7],
    		["Miami", -5],
    	],
    };*/
    
    
    // Example hworldclock.settings.json
    // [["London","0"],["NY","-5"],["Denver","-­6"]]
    
    
    // Uncomment one at a time to test various offsets array scenarios
    //offsets = mockOffsets.zeroOffsets; // should render nothing below primary time
    //offsets = mockOffsets.oneOffset; // should render larger in two rows
    //offsets = mockOffsets.twoOffsets; // should render two in columns
    //offsets = mockOffsets.fourOffsets; // should render in columns
    
    // END TESTING CODE
     
    
    // Load settings
    function loadMySettings() {
    	// Helper function default setting
    	function def (value, def) {return value !== undefined ? value : def;}
    
    	var settings = require('Storage').readJSON(SETTINGSFILE­, true) || {};
    	secondsMode = def(settings.secondsMode, "when unlocked");
    	showSunInfo = def(settings.showSunInfo, true);
    	colorWhenDark = def(settings.colorWhenDark, "green");
    }
    
    
    // Check settings for what type our clock should be
    var _12hour = (require("Storage").readJSON("setting.js­on",1)||{})["12hour"]||false;
    
    // timeout used to update every minute
    var drawTimeout;
    var drawTimeoutSeconds;
    var secondsTimeout;
    
    g.setBgColor(g.theme.bg);
    
    // schedule a draw for the next minute
    function queueDraw() {
    	if (drawTimeout) clearTimeout(drawTimeout);
    		drawTimeout = setTimeout(function() {
    			drawTimeout = undefined;
    			draw();
    		}, 60000 - (Date.now() % 60000));
    }
    
    // schedule a draw for the next second
    function queueDrawSeconds() {
    	if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds);
    		drawTimeoutSeconds = setTimeout(function() {
    			drawTimeoutSeconds = undefined;
    			drawSeconds();
    			//console.log("TO: " + secondsTimeout);
    		}, secondsTimeout - (Date.now() % secondsTimeout));
    }
    
    function doublenum(x) {
    	return x < 10 ? "0" + x : "" + x;
    }
    
    function getCurrentTimeFromOffset(dt, offset) {
    	return new Date(dt.getTime() + offset * 60 * 60 * 1000);
    }
    
    function updatePos() {
    
    	coord = require("Storage").readJSON(LOCATION_FIL­E,1)||  {"lat":0,"lon":0,"location":"-"}; //{"lat":53.3,"lon":10.1,"location":"Pat­tensen"};
    	if (coord.lat != 0 && coord.lon != 0) {
    	//pos = SunCalc.getPosition(Date.now(), coord.lat, coord.lon);	
    	times = SunCalc.getTimes(Date.now(), coord.lat, coord.lon);
    	rise = "^" + times.sunrise.toString().split(" ")[4].substr(0,5);
    	set	= "v" + times.sunset.toString().split(" ")[4].substr(0,5);
    	//noonpos = SunCalc.getPosition(times.solarNoon, coord.lat, coord.lon);
    	} else {
    		rise = null;
    		set  = null;
    	}
    }
    
    
    function drawSeconds() {
    	// get date
    	var d = new Date();
    	var da = d.toString().split(" ");
    
    	// default draw styles
    	g.reset().setBgColor(g.theme.bg).setFont­Align(0, 0);
    
    	// draw time
    	var time = da[4].split(":");
    	var seconds = time[2];
    
    	g.setFont("5x9Numeric7Seg",primaryTimeFo­ntSize - 3);
    	if (g.theme.dark) {
    		if (colorWhenDark == "green") {
    			g.setColor("#22ff05");
    		} else {
    			g.setColor(g.theme.fg);
    		}
    	} else {
    		g.setColor(g.theme.fg);
    	}
    	//console.log("---");
    	//console.log(seconds);
    	if (Bangle.isLocked() && secondsMode != "always") seconds = seconds.slice(0, -1) + ':::'; // we use :: as the font does not have an x
    	//console.log(seconds);
    	g.drawString(`${seconds}`, xyCenterSeconds, yposTime+14, true); 
    	queueDrawSeconds();
    
    }
    
    function draw() {
    	// get date
    	var d = new Date();
    	var da = d.toString().split(" ");
    
    	// default draw styles
    	g.reset().setBgColor(g.theme.bg).setFont­Align(0, 0);
    
    	// draw time
    	var time = da[4].split(":");
    	var hours = time[0],
    	minutes = time[1];
    	
    	
    	if (_12hour){
    		//do 12 hour stuff
    		if (hours > 12) {
    			ampm = "PM";
    			hours = hours - 12;	
    			if (hours < 10) hours = doublenum(hours);	
    		} else {
    			ampm = "AM";	 
    		}	 
    	}	
    
    	//g.setFont(font, primaryTimeFontSize);
    	g.setFont("5x9Numeric7Seg",primaryTimeFo­ntSize);
    	if (g.theme.dark) {
    		if (colorWhenDark == "green") {
    			g.setColor("#22ff05");
    		} else {
    			g.setColor(g.theme.fg);
    		}
    	} else {
    		g.setColor(g.theme.fg);
    	}
    	g.drawString(`${hours}:${minutes}`, xyCenter-10, yposTime, true);
    	
    	// am / PM ?
    	if (_12hour){
    	//do 12 hour stuff
    		//var ampm = require("locale").medidian(new Date()); Not working
    		g.setFont("Vector", 17);
    		g.drawString(ampm, xyCenterSeconds, yAmPm, true);
    	}	
    
    	if (secondsMode != "none") drawSeconds(); // To make sure...
    	
    	// draw Day, name of month, Date	
    	//DATE
    	var localDate = require("locale").date(new Date(), 1);
    	localDate = localDate.substring(0, localDate.length - 5);
    	g.setFont("Vector", 17);
    	g.drawString(require("locale").dow(new Date(), 1).toUpperCase() + ", " + localDate, xyCenter, yposDate, true);
    
    	g.setFont(font, primaryDateFontSize);
    	// set gmt to UTC+0
    	var gmt = new Date(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
    
    	// Loop through offset(s) and render
    	offsets.forEach((offset, index) => {
    	dx = getCurrentTimeFromOffset(gmt, offset[OFFSET_HOURS]);
    	hours = doublenum(dx.getHours());
    	minutes = doublenum(dx.getMinutes());
    
    
    	if (offsets.length === 1) {
    		var date = [require("locale").dow(new Date(), 1), require("locale").date(new Date(), 1)];	
    		// For a single secondary timezone, draw it bigger and drop time zone to second line
    		const xOffset = 30;
    		g.setFont(font, secondaryTimeFontSize).drawString(`${hou­rs}:${minutes}`, xyCenter, yposTime2, true);
    		g.setFont(font, secondaryTimeZoneFontSize).drawString(of­fset[OFFSET_TIME_ZONE], xyCenter, yposTime2 + 30, true);
    
    		// draw Day, name of month, Date
    		g.setFont(font, secondaryTimeZoneFontSize).drawString(da­te, xyCenter, yposDate, true);
    	} else if (index < 3) {
    		// For > 1 extra timezones, render as columns / rows
    		g.setFont(font, secondaryRowColFontSize).setFontAlign(-1­, 0);
    		g.drawString(
    			offset[OFFSET_TIME_ZONE],
    			xcol1,
    			yposWorld + index * 15,
    			true
    		);
    		g.setFontAlign(1, 0).drawString(`${hours}:${minutes}`, xcol2, yposWorld + index * 15, true);
    	}
    	});
    
    	if (showSunInfo) {
    		if (rise != null){
    			g.setFontAlign(-1, 0).setFont("Vector",12).drawString(`${ri­se}`, 10, 3 + yposWorld + 3 * 15, true); // draw rise
    			g.setFontAlign(1, 0).drawString(`${set}`, xcol2, 3 + yposWorld + 3 * 15, true); // draw set
    		} else {
    			g.setFontAlign(-1, 0).setFont("Vector",11).drawString("set city in \'my location\' app!", 10, 3 + yposWorld + 3 * 15, true); 
    		}
    	}
    	//debug settings
    	//g.setFontAlign(1, 0);
    	//g.drawString(secondsMode, xcol2, 3 + yposWorld + 3 * 15, true);
    	//g.drawString(showSunInfo, xcol2, 3 + yposWorld + 3 * 15, true);
    	//g.drawString(colorWhenDark, xcol2, 3 + yposWorld + 3 * 15, true);
    
    	queueDraw();
    	
    	if (secondsMode != "none") queueDrawSeconds();
    }
    
    // clean app screen
    g.clear();
    
    // Init the settings of the app
    loadMySettings();
    
    // Show launcher when button pressed
    Bangle.setUI("clock");
    Bangle.loadWidgets();
    Bangle.drawWidgets();
    
    
    // draw immediately at first, queue update
    draw();
    
    
    if (!Bangle.isLocked())  { // Initial state
    		if (showSunInfo) {
    			if (PosInterval != 0) clearInterval(PosInterval);
    			PosInterval = setInterval(updatePos, 60*10E3);	// refesh every 10 mins
    			updatePos();
    		}
    
    		secondsTimeout =  1000;
    		if (secondsMode != "none") {
    			if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds);
    			drawTimeoutSeconds = undefined;
    		}	
    		if (drawTimeout) clearTimeout(drawTimeout);
    		drawTimeout = undefined;
    		draw(); // draw immediately, queue redraw
    		
      }else{
    		if (secondsMode == "always") secondsTimeout = 1000;
    		if (secondsMode == "when unlocked") secondsTimeout = 10 * 1000;
    		
    		if (secondsMode != "none") {
    			if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds);
    			drawTimeoutSeconds = undefined;
    		}
    		if (drawTimeout) clearTimeout(drawTimeout);
    		drawTimeout = undefined;
    
    		if (showSunInfo) {
    			if (PosInterval != 0) clearInterval(PosInterval);
    			PosInterval = setInterval(updatePos, 60*60E3);	// refesh every 60 mins
    			updatePos();
    		}
    		draw(); // draw immediately, queue redraw
    		
      }
     
    
    Bangle.on('lock',on=>{
      if (!on) { // UNlocked
     console.log("1 i " + process.memory().usage);
    		if (showSunInfo) {
    			if (PosInterval != 0) clearInterval(PosInterval);
    			PosInterval = setInterval(updatePos, 60*10E3);	// refesh every 10 mins
    			updatePos();
    		}
    
    		secondsTimeout =  1000;
    		if (secondsMode != "none") {
    			if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds);
    			drawTimeoutSeconds = undefined;
    		}	
    		if (drawTimeout) clearTimeout(drawTimeout);
    		drawTimeout = undefined;
     console.log("1 m " + process.memory().usage);
    
    		draw(); // draw immediately, queue redraw
    		 console.log("1 o " + process.memory().usage);
    
      }else{  // locked
     console.log("2 i " + process.memory().usage);
    
    		if (secondsMode == "always") secondsTimeout = 1000;
    		if (secondsMode == "when unlocked") secondsTimeout = 10 * 1000;
    		
    		if (secondsMode != "none") {
    			if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds);
    			drawTimeoutSeconds = undefined;
    		}
    		if (drawTimeout) clearTimeout(drawTimeout);
    		drawTimeout = undefined;
     console.log("2 m " + process.memory().usage);
    
    		if (showSunInfo) {
    			if (PosInterval != 0) clearInterval(PosInterval);
    			PosInterval = setInterval(updatePos, 60*60E3);	// refesh every 60 mins
    			updatePos();
    		}
    		draw(); // draw immediately, queue redraw		
     console.log("2 o " + process.memory().usage);
      }
     });
    

    I get this:

    2 i 2104
    2 m 2074
    2 o 2104
    
    1 i 2137
    1 m 2107
    1 o 2137
    
    2 i 2170
    2 m 2140
    2 o 2170
    
    1 i 2203
    1 m 2173
    1 o 2203
    
    2 i 2236
    2 m 2206
    2 o 2236
    

    So after each status change (1 vs. 2) more RAM is used somehow.

    When I remove

    Bangle.loadWidgets();
    Bangle.drawWidgets();
    

    it seems to stop loosing RAM. So my next guess is one of the widgets.
    ...working on it...

About

Avatar for Hank @Hank started