Plugin dev: cannot figure out how to save my conf

Hello,

I am developing a plugin for volumio to get a rotary encoder to change the volume. At the moment I am stuck on the basics, i.e. how to save and load the configuration.
I managed to get my plugin to show on theUI, I can enable or disable it but when I save, the configuration does not stick.
The first time I show the conf page it does not read from the default config.json file either.

I never see the config.json in /data/configuration/miscellanea/myplugin.

I am developing this on a Rpi2 B.

I would really apreciate if someone could point me in the right direction.

config.json

{
  "enabled": {
    "type": "boolean",
    "value": false
  },
  "pina": {
    "type": "number",
    "value": 2
  },
  "pinb": {
    "type": "number",
    "value": 3
  },
  "pinc": {
    "type": "number",
    "value": 4
  }
}

UIConfig.json

{
  "page": {
    "label": "GPIO Rotary Encoder"
  },
  "sections": [
    {
      "id": "re_setup",
      "element": "section",
      "label": "Setup your Rotary Encoder PINs",
      "icon": "fa-plug",
      "onSave": { "type":"controller", "endpoint":"miscellanea/gpio-rotary", "method":"saveTriggers" },
      "saveButton": {
        "label": "Save",
        "data": [
          "pina_setting",
          "pinb_setting",
          "pinc_setting"
        ]
      },
      "content": [
        {
          "id": "pina_setting",
          "element": "select",
          "label": "GPIO for pin A",
          "value": { "value": 2, "label": "2" },
          "options": [
            { "value": 2, "label": "2" },
            { "value": 3, "label": "3" },
            { "value": 4, "label": "4" },
            { "value": 5, "label": "5" },
            { "value": 6, "label": "6" },
            { "value": 7, "label": "7" },
            { "value": 8, "label": "8" },
            { "value": 9, "label": "9" },
            { "value": 10, "label": "10" },
            { "value": 11, "label": "11" },
            { "value": 12, "label": "12" },
            { "value": 13, "label": "13" },
            { "value": 14, "label": "14" },
            { "value": 15, "label": "15" },
            { "value": 16, "label": "16" },
            { "value": 17, "label": "17" },
            { "value": 18, "label": "18" },
            { "value": 19, "label": "19" },
            { "value": 20, "label": "20" },
            { "value": 21, "label": "21" },
            { "value": 22, "label": "22" },
            { "value": 23, "label": "23" },
            { "value": 24, "label": "24" },
            { "value": 25, "label": "25" },
            { "value": 26, "label": "26" },
            { "value": 27, "label": "27" }
          ]
        },
        {
          "id": "pinb_setting",
          "element": "select",
          "label": "GPIO for pin B",
          "value": { "value": 3, "label": "3" },
          "options": [
            { "value": 2, "label": "2" },
            { "value": 3, "label": "3" },
            { "value": 4, "label": "4" },
            { "value": 5, "label": "5" },
            { "value": 6, "label": "6" },
            { "value": 7, "label": "7" },
            { "value": 8, "label": "8" },
            { "value": 9, "label": "9" },
            { "value": 10, "label": "10" },
            { "value": 11, "label": "11" },
            { "value": 12, "label": "12" },
            { "value": 13, "label": "13" },
            { "value": 14, "label": "14" },
            { "value": 15, "label": "15" },
            { "value": 16, "label": "16" },
            { "value": 17, "label": "17" },
            { "value": 18, "label": "18" },
            { "value": 19, "label": "19" },
            { "value": 20, "label": "20" },
            { "value": 21, "label": "21" },
            { "value": 22, "label": "22" },
            { "value": 23, "label": "23" },
            { "value": 24, "label": "24" },
            { "value": 25, "label": "25" },
            { "value": 26, "label": "26" },
            { "value": 27, "label": "27" }
          ]
        },
        {
          "id": "pinc_setting",
          "element": "select",
          "label": "GPIO for pin C",
          "value": { "value": 4, "label": "4" },
          "options": [
            { "value": 2, "label": "2" },
            { "value": 3, "label": "3" },
            { "value": 4, "label": "4" },
            { "value": 5, "label": "5" },
            { "value": 6, "label": "6" },
            { "value": 7, "label": "7" },
            { "value": 8, "label": "8" },
            { "value": 9, "label": "9" },
            { "value": 10, "label": "10" },
            { "value": 11, "label": "11" },
            { "value": 12, "label": "12" },
            { "value": 13, "label": "13" },
            { "value": 14, "label": "14" },
            { "value": 15, "label": "15" },
            { "value": 16, "label": "16" },
            { "value": 17, "label": "17" },
            { "value": 18, "label": "18" },
            { "value": 19, "label": "19" },
            { "value": 20, "label": "20" },
            { "value": 21, "label": "21" },
            { "value": 22, "label": "22" },
            { "value": 23, "label": "23" },
            { "value": 24, "label": "24" },
            { "value": 25, "label": "25" },
            { "value": 26, "label": "26" },
            { "value": 27, "label": "27" }
          ]
        }
      ]
    }
  ]
}

index.js

'use strict';

var libQ = require('kew');
//var fs = require('fs-extra');
var Gpio = require('onoff').Gpio;
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000');

module.exports = GPIORotary;

function GPIORotary(context) {
	var self = this;

	this.context = context;
	this.commandRouter = this.context.coreCommand;
	this.logger = this.context.logger;
	this.configManager = this.context.configManager;
}
// demarrage de Volumio
GPIORotary.prototype.onVolumioStart = function() {
	var self = this;
	var configFile=self.commandRouter.pluginManager.getConfigurationFile(self.context,'config.json');

	self.config = new (require('v-conf'))();
	self.logger.info('GPIO-Rotary pre loadFile ' + configFile);
	self.config.loadFile(configFile);
	self.logger.info('GPIO-Rotary Initialized');
	self.config.print();
};

// charge le fichier config.json
// c'est ce bout de bidule qui doit creer /data/configuration/miscellanea/gpio-rotary/config.json
// si il n'existe pas deja
// depuis /Volumio/app/pluginmanager.js
GPIORotary.prototype.getConfigurationFiles = function() {
	this.logger.info('GPIO-Rotary Got config.json');
	return['config.json'];
};

// Demarrage du plugin
GPIORotary.prototype.onStart = function() {
	var self = this;
	var defer = libQ.defer();

	self.logger.info('GPIO-Rotary Started');
	defer.resolve();
	return defer.promise;
};

// Arret du plugin
GPIORotary.prototype.onStop = function() {
	var self = this;
	var defer = libQ.defer();

	self.logger.info('GPIO-Rotary Stopped');
	defer.resolve();
	return defer.promise;
};

// on utilise cette fonction lorsque on veut acceder a la configuration du plugin
GPIORotary.prototype.getUIConfig = function() {
	var defer = libQ.defer();
	var self = this;

	var lang_code = 'en';

	//self.logger.info('GPIO Rotary - getUIConfig - Start');

	self.commandRouter.i18nJson(__dirname+'/i18n/strings_'+lang_code+'.json',
		__dirname+'/i18n/strings_en.json',
		__dirname +'/UIConfig.json')
		.then(function(uiconf)
		{
			uiconf.sections[0].content[0].value.value = self.config.get('pina');
			uiconf.sections[0].content[0].value.label = self.config.get('pina').toString();
			uiconf.sections[0].content[1].value.value = self.config.get('pinb');
			uiconf.sections[0].content[1].value.label = self.config.get('pinb').toString();
			uiconf.sections[0].content[2].value.value = self.config.get('pinc');
			uiconf.sections[0].content[2].value.label = self.config.get('pinc').toString();
			defer.resolve(uiconf);
		})
		.fail(function()
		{
			defer.reject(new Error());
		});
	return defer.promise;
};

// cette fonction est appelee depuis la page de conf pour enregistrer les parametres
GPIORotary.prototype.saveTriggers = function(data) {
	var defer = libQ.defer();
	var self = this;

	//self.logger.info('GPIO Rotary: Print conf pre save.')
	//self.config.print();

	self.logger.info('GPIO Rotary - Saving PINs');
	//self.config.set('pina', data.pina.value);
	self.config.set('pina', data['pina_setting']['value']);
	self.logger.info('GPIO Rotary - Saved PIN A, value: ' + data.pina_setting.value);
	//self.config.set('pinb', data.pinb.value);
	self.config.set('pinb', data['pinb_setting']['value']);
	//self.config.set('pinc', data.pinc.value);
	self.config.set('pinc', data['pinc_setting']['value']);
	self.logger.info('GPIO Rotary - PINs saved');

	self.commandRouter.pushToastMessage('success',"GPIO Rotary", "Configuration saved");
	defer.resolve();

	//self.logger.info('GPIO Rotary: Print conf post save.')
	//self.config.print();

	return defer.promise;
};

Thanks,

Vincent

Hi,

I faced the same problem a week ago.

Check the config.json file in

/data/plugins/yourCategory/yourPlugin

I guess it is out of sync with your config.json file. If thats true it does not save the configuration (thats what I figured out).
Actually it should save the configuration even if the files are out of sync (see https://github.com/fanciulli/v-conf/blob/master/index.js#L153).

You can also manually call

self.config.save();

to trigger v-conf to write the config into the file.

For easy debugging of your config you can print the content of the config file to console:

self.logger.info(self.config.print());

When you are connected to your pi you can simply run

sudo journalctl -f

to show the ongoing logs of the system to your console.

Hope that helps. :slight_smile:

Stefan

EDIT:
Saw that you have updated your question (?).

You do not see your configuration file in /data/configurations/…?
Thats strange.

What is the output when you change the following method by adding a print of your configuration to console?

[code]GPIORotary.prototype.onVolumioStart = function() {
var self = this;
var configFile=this.commandRouter.pluginManager.getConfigurationFile(this.context,‘config.json’);

this.config = new (require(‘v-conf’))();
self.logger.info('GPIO-Rotary pre loadFile ’ + configFile);
this.config.loadFile(configFile);
self.logger.info(‘GPIO-Rotary Initialized’);

//ADD THIS
self.logger.info(self.config.print());
};[/code]

Hi Stefan,

Thanks for the suggestion, I’ll try this tonight and report back.

Vincent

You are welcome. Let me know if you could fix it.

Well,

Adding that line showed me that the returned configuration was empty, basically because it can’t read /data/configuration/miscellanea/gpio-rotary/config.json.
So I created it copying the config.json from the plugin folder. (But I though it was supposed to use the config.json from the plugin directory as a default conf and set that in the /data/configuration directory when hitting save)

Now I am able to save the conf but it does not appear in the UI.

I have had to change my save routine to things like

self.config.set('pina', data.pina.value);

instead of the

self.config.set('pina', data['pina']);

that I see in other plugins, if I use that I get an error :

info: GPIO Rotary - Saving PINs Mar 13 18:22:46 volumio volumio[2306]: /data/plugins/miscellanea/gpio-rotary/node_modules/v-conf/index.js:197 Mar 13 18:22:46 volumio volumio[2306]: throw Error('The value '+value+' is not a number'); Mar 13 18:22:46 volumio volumio[2306]: ^ Mar 13 18:22:46 volumio volumio[2306]: Error: The value [object Object] is not a number Mar 13 18:22:46 volumio volumio[2306]: at Error (native) Mar 13 18:22:46 volumio volumio[2306]: at Config.forceToType (/data/plugins/miscellanea/gpio-rotary/node_modules/v-conf/index.js:197:20) Mar 13 18:22:46 volumio volumio[2306]: at Config.set (/data/plugins/miscellanea/gpio-rotary/node_modules/v-conf/index.js:106:25) Mar 13 18:22:46 volumio volumio[2306]: at GPIORotary.saveTriggers (/data/plugins/miscellanea/gpio-rotary/index.js:92:14) Mar 13 18:22:46 volumio volumio[2306]: at CoreCommandRouter.executeOnPlugin (/volumio/app/index.js:931:29) Mar 13 18:22:46 volumio volumio[2306]: at Socket.<anonymous> (/volumio/app/plugins/user_interface/websocket/index.js:479:38) Mar 13 18:22:46 volumio volumio[2306]: at emitTwo (events.js:106:13) Mar 13 18:22:46 volumio volumio[2306]: at Socket.emit (events.js:191:7) Mar 13 18:22:46 volumio volumio[2306]: at Socket.onevent (/volumio/node_modules/socket.io/lib/socket.js:348:8) Mar 13 18:22:46 volumio volumio[2306]: at Socket.onpacket (/volumio/node_modules/socket.io/lib/socket.js:308:12)

So I’m assuming there is something wrong in the way my conf is handled but what?

I’ll try to get more time on this later this week.

Thanks a lot for your input!

Vincent

Hello Vincent,

yes, you have a mistake in your config:

I have marked the fields red. Remove the quotes (") here. Take a look on the value of “enabled”. There are no quotes either. :slight_smile:
Remove them and then everything should work even with

self.config.set('pina', data['pina']);

:slight_smile:

Hope that helps.

Stefan