Turn your Volumio Pi into a FM radio station

Tell us how you made up your Volumio powered Project

Ads helps Volumio remain Free and Open Source. Please consider donating to help us continue to serve you.

Turn your Volumio Pi into a FM radio station

Postby Randy » Sun Apr 29 2018 15:34

Greetings,
Using a FM transmitter module and the FMXmtr plug-in I created to control it you can broadcast your favorite music from a Raspberry Pi with Volumio installed.

The transmitter module can be found on Ebay and Amazon. See links below. Ebay is cheaper, but takes longer to get because they are coming on the slow boat from China.

Ebay - https://www.ebay.com/sch/i.html?_odkw=FM+Radio+Transmitter+Module+V2+0&_osacat=0&_from=R40&_trksid=m570.l1313&_nkw=FM+Radio+Transmitter+Module+V2.0&_sacat=0

Amazon - https://www.amazon.com/Transmitter-Module-Digital-Arduino-Microphone/dp/B076KR12VJ/ref=sr_1_4?ie=UTF8&qid=1525012149&sr=8-4&keywords=FM+Radio+Transmitter+Module+V2.0

These are I2C modules based on the KT-0803K FM transmitter on an IC. Any I2C module based on the KT-0803 series should work.

Connecting to a Pi requires 4 wires. Connect VCC (3.3vdc), ground, SDA and SCL to the respective pins on the 40-pin GPIO header.
Pin 1 = 3.3vdc
Pin 3 = GPIO2 / SDA
Pin 5 = GPIO3 / SCL
Pin 9 = ground
Note: If pins 3 and 5 (GPIO2 and GPIO3) have been configured for in or out signal I@C will note work.

Audio is a 3.5mm audio jack. You can connect directly to the audio out on the PI, but the sound quality is not that great. Recommend a USB sound card or a DAC.

Final connection is the antenna. A piece of wire soldered to the antenna connection. Optimal wire length is 5 foot. Shorter lengths still work. I used a 10 inch wire for testing and was able to pick up the signal about 75 yards away with RF gain set at full power.

I created a plug-in to control the transmitter from within Volumio. Pushed it to git hub. This is my first time writing a plug-in. First time using GitHub. According to documentation it should go to the Volumio maintainers for review and then get put in to the official plug-ins if they agree with it, provided I did everything correctly. I'll post the required files below in case I didn't publish it correctly. This way anybody who want to use it can create a blank plug-in and paste these into it.

The required files are "install.sh", "package.json", "config.json", "index.js", "UIConfig.json" and "strings_en.json". The plug-in folder is labeled "fmxmtr". Except for "strings_en.json", all files go in "fmxmtr". "strings_en.json" goes in "fmxmtr/i18n".

install.sh
Code: Select all
#!/bin/bash

echo "Installing fmxmtr Dependencies"
sudo apt-get update
# Install the required packages via apt-get

echo "Installing build-essentials"
sudo apt-get -y install build-essential --no-install-recommends

echo "Installing I2C-tools"
sudo apt-get -y install i2c-tools --no-install-recommends

echo "Installing base functionality for working with a Raspberry Pi from Node.js "
npm install raspi --no-install-recommends


# If you need to differentiate install for armhf and i386 you can get the variable like this
#DPKG_ARCH=`dpkg --print-architecture`
# Then use it to differentiate your install

#requred to end the plugin install
echo "plugininstallend"


package.json
Code: Select all
{
   "name": "fmxmtr",
   "version": "1.0.1",
   "description": "Set up and control I2C FM transmitter module by Electhouse based on KT-0803K fm transmitter chip",
   "main": "index.js",
   "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
   },
   "author": "Randy Bancroft",
   "license": "ISC",
   "volumio_info": {
      "prettyName": "FM Transmitter",
      "icon": "fa-wifi",
      "plugin_type": "miscellanea"
   },
   "dependencies": {
      "fs-extra": "^0.28.0",
      "kew": "^0.7.0",
      "v-conf": "^1.4.0"
   }
}


config.json
Code: Select all
{
    "I2C_BUS": {
    "type": "number",
    "value": "1"
  },
    "I2C_ADDRESS": {
    "type": "text",
    "value": "3e"
  },
    "Freq": {
    "type": "number",
    "value": "94"
  },
    "BaseBoost": {
    "type": "number",
    "value": "2"
  },
    "RFGain": {
    "type": "number",
    "value": "15"
  },
    "MuteAudio": {
    "type": "boolean",
    "value": false
  },
    "MonoAudio": {
    "type": "boolean",
    "value": false
  },
    "PGAMod": {
    "type": "number",
    "value": "0"
  },
    "PGAmp": {
    "type": "number",
    "value": "12"
  },
    "PltAdj": {
    "type": "number",
    "value": "0"
  },
    "PhTCnst": {
    "type": "number",
    "value": "0"
  },
    "PDPA": {
    "type": "boolean",
    "value": false
  },
   "StartUp": {
    "type": "boolean",
    "value": false
  }
}


index.js
Code: Select all
'use strict';

var libQ = require('kew');
var fs=require('fs-extra');
var config = new (require('v-conf'))();
var exec = require('child_process').exec;
var execSync = require('child_process').execSync;

var shell = require('shelljs');

// Create ShellCommand variable.  It is used in several functions
var ShellCommand = '';

// Define variables to hold register values read from transmitter module
var Reg0x00 = 0;
var Reg0x01 = 0;
var Reg0x02 = 0;
var Reg0x04 = 0;
var Reg0x0B = 0;
var Reg0x10 = 0;
var Reg0x12 = 0;
var Reg0x13 = 0;

// Define variables for decoded register values
var FreqRead = 0;
var BaseBoostRead = 0;
var RFGainRead = 0;
var MuteAudioRead = 0;
var MonoAudioRead = 0;
var PGAModRead = 0;
var PGAmpRead = 0;
var PltAdjRead = 0;
var PhTCnStRead = 0;
var PDPARead = false;

// Define variables for data read from conf.json
var FreqStored=0;
var BaseBoostStored=0;
var RFGainStored=0;
var MuteAudioStored=false;
var MonoAudioStored=false;
var PGAModStored=0;
var PGAmpStored=0;
var PltAdjStored=0;
var PhTCnstStored=0;
var PDPAStored=false;
var StartUpStored=false;




module.exports = Controllerfmxmtr;
function Controllerfmxmtr(context) {
   var self = this;

   this.context = context;
   this.commandRouter = this.context.coreCommand;
   this.logger = this.context.logger;
   this.configManager = this.context.configManager;

}


Controllerfmxmtr.prototype.onVolumioStart = function()
{
   var self = this;
   var configFile=this.commandRouter.pluginManager.getConfigurationFile(this.context,'config.json');
   this.config = new (require('v-conf'))();
   this.config.loadFile(configFile);

// check to see if config.json exists
    var checkfile = ("/bin/cp " + configFile + " /tmp/config.txt");
    var exists = false;
    try {
   var cp3 = execSync(checkfile);
   exists = true;
   } catch (err) {
   self.logger.info('fmxmtr config.json does not exist');
   exists = false;
   }

    if(exists){
// Disable broadcasting.  a.k.a. Airplane mode
    ShellCommand = 'i2cset -y ' + this.config.get('I2C_BUS') + ' 0x' + this.config.get('I2C_ADDRESS') + ' 0x0B 0x20';
    shell.exec(ShellCommand);
    self.logger.info('Disabled RF output');

// Config.json exists, read user configuration from config.json and write to transmitter module
// I2C_BUS
        var I2CBusSave = this.config.get('I2C_BUS');
// I2C_ADDRESS
        var I2CAddressSave = this.config.get('I2C_ADDRESS');
// Freq
        var FreqSave = this.config.get('Freq');
        FreqSave = (FreqSave * 1000)/50;
// Convert config.json values to register values
// Frequency is 12 bits divided over three registers
// Register 0x02 bit 0x07 = Freq bit 0x01
// Register 0x00 bits 0x07 to 0x00 = Freq bits 0x08 to 0x01
// Register 0x01 bits 0x02 to 0x00 = Freq bits 0x11 to 0x09
// Split Freq into three registers
        var Reg0x02Freq = (FreqSave & 0x0001) *8;
        var Reg0x00Freq = (FreqSave / 2) & 0x00ff;
        var Reg0x01Freq = ((FreqSave & 0x0600) / 512);
// BaseBoost
        var BaseBoostSave = this.config.get('BaseBoost');
// BaseBoost is two bits in one register
// Register 0x04 bits 0x01 to 0x00 = BaseBoost bits 0x01 to 0x00
        var Reg0x04BaseBoost = (BaseBoostSave & 0x03);
// RFGain
        var RFGainSave = this.config.get('RFGain');
// RFGain is 4 bits divided over tthree registers
// Register 0x02 bit 0x06 = RFGain bit 0x03
// Register 0x13 bit 0x07 = RFGain bit 0x02
// Register 0x01 bits 0x07 to 0x06 - RFGain bits 0x01 to 0x00
        var Reg0x02FRGain = (RFGainSave & 0x08) * 8;
        var Reg0x13FRGain = (RFGainSave & 0x04) * 32;
        var Reg0x01FRGain = (RFGainSave & 0x03) * 64;
// MuteAudio
        var MuteAudioSave = this.config.get('MuteAudio');
// MuteAudio is one bit in one register
// Register 0x02 bit 0x03 = MuteAudio logic state
        var Reg0x02MuteAudio = 0x00;
        if (MuteAudioSave){
            Reg0x02MuteAudio = 0x08;
        } else {
            Reg0x02MuteAudio = 0x00;
        };
// MonoAudio
        var MonoAudioSave = this.config.get('MonoAudio');
// MonoAudio is one bit in one register
// Register 0x04 bit 0x06 = MonoAudio logic state
        var Reg0x04MonoAudio = 0x00;
        if (MonoAudioSave){
            Reg0x04MonoAudio = 0x40;
        } else {
            Reg0x04MonoAudio = 0x00;
        };
// PGAMod
        var PGAModSave = this.config.get('PGAMod');
// PGAMod is three bits in one register
// Register 0x10 bit 0x00 = PGAMod bit 0x00
        var Reg0x10PGAMod = PGAModSave
// PGAmp
        var PGAmpSave = this.config.get('PGAmp');
// PGAmp is 5 bits divided over two registers
// Register 0x01 bits 0x05 to 0x03 = PGAmp bits 0x04 to 0x02
// Register 0x04 bits 0x05 to 0x04 - PGAmp bits 0x01 to 0x00
        if (PGAmpSave < 0){
                PGAmpSave = PGAmpSave * -1;
            }
            else{
                PGAmpSave = (PGAmpSave *1) + 16;
                };
        var Reg0x01PGAmp = (PGAmpSave & 0x1c) * 2;
        var Reg0x04PGAmp = (PGAmpSave & 0x03) * 16;
// PltAdj
        var PltAdjSave = this.config.get('PltAdj');
// PltAdj is one bit in one register
// Register 0x02 bit 0x02 = PltAdj bit 0x00
        var Reg0x02PltAdj = (PltAdjSave & 0x01) * 4;
// PhTCnst
        var PhTCnstSave = this.config.get('PhTCnst');
// PhTCnst is one bit in one register
// Register 0x02 bit 0x00 = PhTCnst bit 0x00
        var Reg0x02PhTCnst = (PhTCnstSave & 0x01);
// PDPA
        var PDPASave = this.config.get('PDPA');
// PDPA is one bit in one register
// Register 0x0B bit 0x05 = PDPA logic state
        var Reg0x0BPDPA = 0x00;
        if (PDPASave){
            Reg0x0BPDPA = 0x20;
        } else {
            Reg0x0BPDPA = 0x00;
        };
// combine all bit per register
// Register 0x00 is made up of Reg0x00Freq only
        var Reg0x00Write = Reg0x00Freq;
// Register 0x01 is made up of Reg0x01FRGain, Reg0x01PGAmp and Reg0x01Freq
        var Reg0x01Write = (Reg0x01FRGain + Reg0x01PGAmp + Reg0x01Freq);
//Register 0x02 is made up of Reg0x02Freq, Reg0x02FRGain, Reg0x02MuteAudio, Reg0x02PltAdj and Reg0x02PhTCnst
        var Reg0x02Write = (Reg0x02 & 0x32) + (Reg0x02Freq + Reg0x02FRGain + Reg0x02MuteAudio + Reg0x02PltAdj + Reg0x02PhTCnst);
// Register 0x04 is made up of Reg0x04MonoAudio, Reg0x04PGAmp and Reg0x04BaseBoost
        var Reg0x04Write = (Reg0x04 & 0x8c) + (Reg0x04MonoAudio + Reg0x04PGAmp + Reg0x04BaseBoost);
// Register 0x0b is made up of Reg0x0BPDPA only
        var Reg0x0BWrite = (Reg0x0B & 0xdf) + Reg0x0BPDPA;
// Register 0x10 is made up of Reg0x10PGAMod only
        var Reg0x10Write = (Reg0x10 & 0xfe) + Reg0x10PGAMod;
// Register 0x13 is made up of  only Reg0x13FRGain
        var Reg0x13Write = (Reg0x13 & 0x7f) + Reg0x13FRGain;
// Write registers
        ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x00 0x' + Reg0x00Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x01 0x' + Reg0x01Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x02 0x' + Reg0x02Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x04 0x' + Reg0x04Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x0B 0x' + Reg0x0BWrite.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x10 0x' + Reg0x10Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x13 0x' + Reg0x13Write.toString(16);
        shell.exec(ShellCommand);

// Check to see if user desires to start transmitting on Volumio Start
        if (this.config.get('StartUp')){
            ShellCommand = 'i2cset -y ' + this.config.get('I2C_BUS') + ' 0x' + this.config.get('I2C_ADDRESS') + ' 0x0B 0x00';
            shell.exec(ShellCommand);
        }
        else
        {
            ShellCommand = 'i2cset -y ' + this.config.get('I2C_BUS') + ' 0x' + this.config.get('I2C_ADDRESS') + ' 0x0B 0x20';
            shell.exec(ShellCommand);
        };
    }
    else {
// config.json does not exist, create it, fill with defaults and write defaults to registers on transmitter module
// Disable broadcasting using default values.  a.k.a. Airplane mode
        shell.exec('i2cset -y 1 0x3e 0x0B 0x20');
        self.logger.info('Disabled RF output');

// Create file
        ShellCommand = ('echo {} > ' + configFile);
        shell.exec(ShellCommand);
        self.logger.info('Created fmxmtr config.json');

// Fill it with default values
        self.config.set('I2C_BUS',1);
        self.config.set('I2C_ADDRESS',"3e");
        self.config.set('Freq',"94.5");
        self.config.set('BaseBoost',0);
        self.config.set('RFGain',15);
        self.config.set('MuteAudio',false);
        self.config.set('MonoAudio',false);
        self.config.set('PGAMod',0);
        self.config.set('PGAmp',0);
        self.config.set('PltAdj',0);
        self.config.set('PhTCnst',0);
        self.config.set('PDPA',false);
        self.config.set('StartUp',true);

// Set default values on transmiter module
    // Write default registers
        shell.exec('i2cset -y 1 0x3e 0x00 0xb1');
        shell.exec('i2cset -y 1 0x3e 0x01 0xe3');
        shell.exec('i2cset -y 1 0x3e 0x02 0x40');
        shell.exec('i2cset -y 1 0x3e 0x04 0x04');
        shell.exec('i2cset -y 1 0x3e 0x0b 0x00');
        shell.exec('i2cset -y 1 0x3e 0x10 0xa8');
        shell.exec('i2cset -y 1 0x3e 0x13 0x80');
    };

    return libQ.resolve();
}

Controllerfmxmtr.prototype.onStart = function() {
    var self = this;
   var defer=libQ.defer();


// Read registers starting values from module
    Reg0x00 = shell.exec('i2cget -y 1 0x3e 0x00');
    Reg0x01 = shell.exec('i2cget -y 1 0x3e 0x01');
    Reg0x02 = shell.exec('i2cget -y 1 0x3e 0x02');
    Reg0x04 = shell.exec('i2cget -y 1 0x3e 0x04');
    Reg0x0B = shell.exec('i2cget -y 1 0x3e 0x0B');
    Reg0x10 = shell.exec('i2cget -y 1 0x3e 0x10');
    Reg0x12 = shell.exec('i2cget -y 1 0x3e 0x12');
    Reg0x13 = shell.exec('i2cget -y 1 0x3e 0x13');

// Decode registers into working values
    FreqRead = ((Reg0x01 & 0x07) * 512) + (Reg0x00 * 2) + ((Reg0x02 & 0x80)/128);
    BaseBoostRead = (Reg0x04 & 0x03);
    RFGainRead = ((Reg0x02 & 0x40)/8) + ((Reg0x13 & 0x80)/32) + ((Reg0x01 & 0xc0)/64);
    MuteAudioRead = ((Reg0x02 & 0x08)/8);
    MonoAudioRead = ((Reg0x04 & 0x40)/64);
    PGAModRead = (Reg0x10 & 1);
    PGAmpRead = ((Reg0x01 & 0x38)/2) + ((Reg0x04 & 0x30)/16);
    PltAdjRead = ((Reg0x02 & 0x04)/4);
    PhTCnStRead = (Reg0x02 & 0x01);
    PDPARead = ((Reg0x0B & 0x20)/32);


// Once the Plugin has successfull started resolve the promise
   defer.resolve();

    return defer.promise;
};

Controllerfmxmtr.prototype.onStop = function() {
    var self = this;
    var defer=libQ.defer();

// Once the Plugin has successfull stopped resolve the promise
    defer.resolve();

    return libQ.resolve();
};

Controllerfmxmtr.prototype.onRestart = function() {
    var self = this;
// Optional, use if you need it


};


// Configuration Methods -----------------------------------------------------------------------------

Controllerfmxmtr.prototype.getUIConfig = function() {
    var defer = libQ.defer();
    var self = this;

    var lang_code = this.commandRouter.sharedVars.get('language_code');

    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('I2C_BUS');
                uiconf.sections[0].content[0].value.label = self.config.get('I2C_BUS');
                uiconf.sections[0].content[1].value = self.config.get('I2C_ADDRESS');
                uiconf.sections[0].content[2].config.bars[0].value = self.config.get('Freq');
                uiconf.sections[0].content[3].value.value = self.config.get('BaseBoost');
                uiconf.sections[0].content[3].value.label = self.config.get('BaseBoost');
                uiconf.sections[0].content[4].value.value = self.config.get('RFGain');
                uiconf.sections[0].content[4].value.label = self.config.get('RFGain');
                uiconf.sections[0].content[5].value = self.config.get('MuteAudio');
                uiconf.sections[0].content[6].value = self.config.get('MonoAudio');
                uiconf.sections[0].content[7].value.value = self.config.get('PGAMod');
                uiconf.sections[0].content[7].value.label = self.config.get('PGAMod');
                if (self.config.get('PGAMod') == 0) {
                    uiconf.sections[0].content[8].config.bars[0].value = (self.config.get('PGAmp') - (self.config.get('PGAmp') % 5));
                    uiconf.sections[0].content[8].config.bars[0].step = 5;
                } else {
                    uiconf.sections[0].content[8].config.bars[0].step = 1;
                    uiconf.sections[0].content[8].config.bars[0].value = self.config.get('PGAmp');
                };
                uiconf.sections[0].content[9].value.value = self.config.get('PltAdj');
                uiconf.sections[0].content[9].value.label = self.config.get('PltAdj');
                uiconf.sections[0].content[10].value.value = self.config.get('PhTCnst');
                uiconf.sections[0].content[10].value.label = self.config.get('PhTCnst');
                uiconf.sections[0].content[11].value = self.config.get('PDPA');
                uiconf.sections[0].content[12].value = self.config.get('StartUp');
                   
                defer.resolve(uiconf);
            }
        )
    .fail(function()
        {
            defer.reject(new Error());
        }
    );

return defer.promise;
};


Controllerfmxmtr.prototype.setUIConfig = function(data) {
   var self = this;
   //Perform your installation tasks here

};

Controllerfmxmtr.prototype.getConf = function(varName) {
   var self = this;
//Perform your installation tasks here
};

Controllerfmxmtr.prototype.setConf = function(varName, varValue) {
   var self = this;
//Perform your installation tasks here
};

// define what happens when the user clicks the 'save' button on the settings page
// save new values and write them to the transmitter module
Controllerfmxmtr.prototype.SaveFMXmtrOptions = function(data) {
    var self = this;
    var successful = true;

// Save I2C_BUS
    var I2CBusSave = data.I2C_BUS.value;
    self.config.set('I2C_BUS',I2CBusSave);
   
// Save I2C_ADDRESS
    var I2CAddressSave = data.I2C_ADDRESS;
    self.config.set('I2C_ADDRESS',I2CAddressSave);

// Save Freq
    var FreqSave = data.Freq;
    self.config.set('Freq',FreqSave);
    FreqSave = (FreqSave * 1000)/50;

// Convert save values to register values
// Frequency is 12 bits divided over three registers
// Register 0x02 bit 0x07 = Freq bit 0x01
// Register 0x00 bits 0x07 to 0x00 = Freq bits 0x08 to 0x01
// Register 0x01 bits 0x02 to 0x00 = Freq bits 0x11 to 0x09
// Split Freq into three registers
    var Reg0x02Freq = (FreqSave & 0x0001) *8;
    var Reg0x00Freq = (FreqSave / 2) & 0x00ff;
    var Reg0x01Freq = ((FreqSave & 0x0600) / 512);
   
// Save BaseBoost
    var BaseBoostSave = data.BaseBoost.value;
    self.config.set('BaseBoost',BaseBoostSave);
   
// Convert save values to register values
// BaseBoost is two bits in one register
// Register 0x04 bits 0x01 to 0x00 = BaseBoost bits 0x01 to 0x00
    var Reg0x04BaseBoost = (BaseBoostSave & 0x03);

// Save RFGain
    var RFGainSave = data.RFGain.value;
    self.config.set('RFGain',RFGainSave);

// Convert save values to register values
// RFGain is 4 bits divided over tthree registers
// Register 0x02 bit 0x06 = RFGain bit 0x03
// Register 0x13 bit 0x07 = RFGain bit 0x02
// Register 0x01 bits 0x07 to 0x06 - RFGain bits 0x01 to 0x00
    var Reg0x02FRGain = (RFGainSave & 0x08) * 8;
    var Reg0x13FRGain = (RFGainSave & 0x04) * 32;
    var Reg0x01FRGain = (RFGainSave & 0x03) * 64;

// Save MuteAudio
    var MuteAudioSave = data.MuteAudio;
    self.config.set('MuteAudio',MuteAudioSave);

// Convert save values to register values
// MuteAudio is one bit in one register
// Register 0x02 bit 0x03 = MuteAudio logic state
    var Reg0x02MuteAudio = 0x00;
    if (MuteAudioSave){
        Reg0x02MuteAudio = 0x08;
    } else {
        Reg0x02MuteAudio = 0x00;
    };

// Save MonoAudio
    var MonoAudioSave = data.MonoAudio;
    self.config.set('MonoAudio',MonoAudioSave);

// Convert save values to register values
// MonoAudio is one bit in one register
// Register 0x04 bit 0x06 = MonoAudio logic state
    var Reg0x04MonoAudio = 0x00;
    if (MonoAudioSave){
        Reg0x04MonoAudio = 0x40;
    } else {
        Reg0x04MonoAudio = 0x00;
    };

// Save PGAMod
    var PGAModSave = data.PGAMod.value;
    self.config.set('PGAMod',PGAModSave);

// Convert save values to register values
// PGAMod is three bits in one register
// Register 0x10 bit 0x00 = PGAMod bit 0x00
    var Reg0x10PGAMod = PGAModSave

// Save PGAmp
    var PGAmpSave = data.PGAmp;
    self.config.set('PGAmp',PGAmpSave);

// Convert save values to register values
// PGAmp is 5 bits divided over two registers
// Register 0x01 bits 0x05 to 0x03 = PGAmp bits 0x04 to 0x02
// Register 0x04 bits 0x05 to 0x04 - PGAmp bits 0x01 to 0x00
    if (PGAmpSave < 0){
            PGAmpSave = PGAmpSave * -1;
        }
        else{
            PGAmpSave = (PGAmpSave *1) + 16;
            };
    var Reg0x01PGAmp = (PGAmpSave & 0x1c) * 2;
    var Reg0x04PGAmp = (PGAmpSave & 0x03) * 16;

// Save PltAdj
    var PltAdjSave = data.PltAdj.value;
    self.config.set('PltAdj',PltAdjSave);

// Convert save values to register values
// PltAdj is one bit in one register
// Register 0x02 bit 0x02 = PltAdj bit 0x00
     var Reg0x02PltAdj = (PltAdjSave & 0x01) * 4;

// Save PhTCnst
    var PhTCnstSave = data.PhTCnst.value;
    self.config.set('PhTCnst',PhTCnstSave);

// Convert save values to register values
// PhTCnst is one bit in one register
// Register 0x02 bit 0x00 = PhTCnst bit 0x00
    var Reg0x02PhTCnst = (PhTCnstSave & 0x01);

// Save PDPA
    var PDPASave = data.PDPA;
    self.config.set('PDPA',PDPASave);

// Save StartUp
    var StartUpSave = data.StartUp;
    self.config.set('StartUp',StartUpSave);

// Convert save values to register values
// PDPA is one bit in one register
// Register 0x0B bit 0x05 = PDPA logic state
    var Reg0x0BPDPA = 0x00;
    if (PDPASave){
        Reg0x0BPDPA = 0x20;
    } else {
        Reg0x0BPDPA = 0x00;
    };

// combine all bit per register
// Register 0x00 is made up of Reg0x00Freq only
    var Reg0x00Write = Reg0x00Freq;
// Register 0x01 is made up of Reg0x01FRGain, Reg0x01PGAmp and Reg0x01Freq
    var Reg0x01Write = (Reg0x01FRGain + Reg0x01PGAmp + Reg0x01Freq);
//Register 0x02 is made up of Reg0x02Freq, Reg0x02FRGain, Reg0x02MuteAudio, Reg0x02PltAdj and Reg0x02PhTCnst
    var Reg0x02Write = (Reg0x02 & 0x32) + (Reg0x02Freq + Reg0x02FRGain + Reg0x02MuteAudio + Reg0x02PltAdj + Reg0x02PhTCnst);
// Register 0x04 is made up of Reg0x04MonoAudio, Reg0x04PGAmp and Reg0x04BaseBoost
    var Reg0x04Write = (Reg0x04 & 0x8c) + (Reg0x04MonoAudio + Reg0x04PGAmp + Reg0x04BaseBoost);
// Register 0x0b is made up of Reg0x0BPDPA only
    var Reg0x0BWrite = (Reg0x0B & 0xdf) + Reg0x0BPDPA;
// Register 0x10 is made up of Reg0x10PGAMod only
    var Reg0x10Write = (Reg0x10 & 0xfe) + Reg0x10PGAMod;
// Register 0x13 is made up of  only Reg0x13FRGain
    var Reg0x13Write = (Reg0x13 & 0x7f) + Reg0x13FRGain;
// Write registers
    //shell.exec('i2cset -y 1 0x3e 0x00 0x00');
    ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x00 0x' + Reg0x00Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x01 0x' + Reg0x01Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x02 0x' + Reg0x02Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x04 0x' + Reg0x04Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x0B 0x' + Reg0x0BWrite.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x10 0x' + Reg0x10Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = 'i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x13 0x' + Reg0x13Write.toString(16);
    shell.exec(ShellCommand);
};


UIConfig.json
Code: Select all
{
    "page": {
       "label": "FMXmtr CONFIGURATION"
   },
    "sections": [
   {
        "id": "fmxmtr",
       "element": "switch",
       "label": "TRANSLATE.FMXMTR.LABEL",
       "icon": "volume-off",
       "description": "TRANSLATE.FMXMTR.DESC",
       "value": true,
       "onSave": {
            "type":"controller",
            "endpoint":"miscellanea/fmxmtr",
            "method":"SaveFMXmtrOptions"
       },
       "saveButton": {
            "label": "TRANSLATE.SAVE",
            "data": [
                "I2C_BUS",
                "I2C_ADDRESS",
                "Freq",
                "BaseBoost",
                "RFGain",
                "MuteAudio",
                "MonoAudio",
                "PGAMod",
                "PGAmp",
                "PltAdj",
                "PhTCnst",
                "PDPA",
                "StartUp"
            ]
       },
        "content": [
            {
                "id": "I2C_BUS",
                "element": "select",
                "label": "TRANSLATE.I2CBUS.LABEL",
                "description": "TRANSLATE.I2CBUS.DESC",
                "doc": "TRANSLATE.I2CBUS.DOC",
                "value": {"value": 1 ,"label": "1 - Default"},
                "options": [
                     {
                       "value": 1,
                       "label": "1 - Default"
                     },
                     {
                       "value": 0,
                       "label": "0 - Alternate bus"
                     }
                   ]
            },
            {
                "id": "I2C_ADDRESS",
                "element": "input",
                "type": "text",
                "label": "TRANSLATE.I2CADDRESS.LABEL",
                "description": "TRANSLATE.I2CADDRESS.DESC",
                "doc": "TRANSLATE.I2CADDRESS.DOC",
                "attributes": [
                      {"placeholder": "3E"}, {"maxlength": 2}
                    ],
                "value": "3E"
            },
            {
                "id": "Freq",
                "element": "equalizer",
                "label": "TRANSLATE.FREQ.LABEL",
                "description": "TRANSLATE.FREQ.DESC",
                "doc": "TRANSLATE.FREQ.DOC",
                "config": {
                    "orientation": "horizontal",
                    "bars": [
                        {
                        "min": 70.1,
                        "max": 107.9,
                        "step": ".2",
                        "value": "94.5",
                        "tooltip": "always"
                        }
                    ]
                 }
            },
            {
                "id": "BaseBoost",
                "element": "select",
                "label": "TRANSLATE.BASEBOOST.LABEL",
                "description": "TRANSLATE.BASEBOOST.DESC",
                "doc": "TRANSLATE.BASEBOOST.DOC",
                "value": {"value": 0 ,"label": "0 = 0db - Default"},
                "options": [
                    {
                       "value": 0,
                       "label": "0 = 0db - Default"
                    },
                    {
                       "value": 1,
                       "label": "1 = 5db"
                    },
                    {
                       "value": 2,
                       "label": "2 = 11db"
                    },
                    {
                       "value": 3,
                       "label": "3 = 17db"
                     }
                   ]
            },
            {
                "id": "RFGain",
                "element": "select",
                "label": "TRANSLATE.RFGAIN.LABEL",
                "description": "TRANSLATE.RFGAIN.DESC",
                "doc": "TRANSLATE.RFGAIN.DOC",
                "value": {"value": 15 ,"label": "15 = 108 dBuV - Default"},
                "options": [
                    {
                       "value": 0,
                       "label": "0 = 95.5 dBuV"
                    },
                    {
                       "value": 1,
                       "label": "1 = 96.5 dBuV"
                    },
                    {
                       "value": 2,
                       "label": "2 = 97.5 dBuV"
                    },
                    {
                       "value": 3,
                       "label": "3 = 98.2 dBuV"
                     },
                    {
                       "value": 4,
                       "label": "4 = 98.9 dBuV"
                    },
                    {
                       "value": 5,
                       "label": "5 = 100 dBuV"
                    },
                    {
                       "value": 6,
                       "label": "6 = 101.5 dBuV"
                    },
                    {
                       "value": 7,
                       "label": "7 = 102.8 dBuV"
                    },
                    {
                       "value": 8,
                       "label": "8 = 105.1 dBuV"
                    },
                    {
                       "value": 9,
                       "label": "9 = 105.6 dBuV"
                    },
                    {
                       "value": 10,
                       "label": "10 = 106.2 dBuV"
                    },
                    {
                       "value": 11,
                       "label": "11 = 106.5 dBuV"
                    },
                    {
                       "value": 12,
                       "label": "12 = 107 dBuV"
                    },
                    {
                       "value": 13,
                       "label": "13 = 107.4 dBuV"
                    },
                    {
                       "value": 14,
                       "label": "14 = 107.7 dBuV"
                    },
                    {
                       "value": 15,
                       "label": "15 = 108 dBuV - Default"
                    }
                ]
            },
            {
                "id": "MuteAudio",
                "element": "switch",
                "label": "TRANSLATE.MUTE.LABEL",
                "description": "TRANSLATE.MUTE.DESC",
                "doc": "TRANSLATE.MUTE.DOC",
                "value": false
            },
            {
                "id": "MonoAudio",
                "element": "switch",
                "label": "TRANSLATE.MONO.LABEL",
                "description": "TRANSLATE.MONO.DESC",
                "doc": "TRANSLATE.MONO.DOC",
                "value": false
            },
            {
                "id": "PGAMod",
                "element": "select",
                "label": "TRANSLATE.PGAMOD.LABEL",
                "description": "TRANSLATE.PGAMOD.DESC",
                "doc": "TRANSLATE.PGAMOD.DOC",
                "value": {"value": 0 ,"label": "0 = 4db - Default"},
                "options": [
                     {
                        "value": 0,
                        "label": "0 = 4db - Default"
                     },
                     {
                        "value": 1,
                        "label": "1 = 1db"
                     }
                   ]
            },
            {
                "id": "PGAmp",
                "element": "equalizer",
                "label": "TRANSLATE.PGAMP.LABEL",
                "description": "TRANSLATE.PGAMP.DESC",
                "doc": "TRANSLATE.PGAMP.DOC",
                "config": {
                    "orientation": "horizontal",
                    "bars": [
                        {
                        "min": -15,
                        "max": 15,
                        "step": "1",
                        "value": "0",
                        "tooltip": "always"
                        }
                    ]
                       
                }
            },
            {
                "id": "PltAdj",
                "element": "select",
                "label": "TRANSLATE.PLTADJ.LABEL",
                "description": "TRANSLATE.PLTADJ.DESC",
                "doc": "TRANSLATE.PLTADJ.DOC",
                "value": {"value": 0 ,"label": "0 (Low) - Default"},
                "options": [
                     {
                        "value": 0,
                        "label": "0 = Low - Default"
                     },
                     {
                        "value": 1,
                        "label": "1 = High"
                     }
                   ]
            },
            {
                "id": "PhTCnst",
                "element": "select",
                "label": "TRANSLATE.PHTCNST.LABEL",
                "description": "TRANSLATE.PHTCNST.DESC",
                "doc": "TRANSLATE.PHTCNST.DOC",
                "value": {"value": 0 ,"label": "0 = 75 µs US - Default"},
                "options": [
                     {
                        "value": 0,
                        "label": "0 = 75 µs US - Default"
                     },
                                      {
                        "value": 1,
                        "label": "1 = 50 µs"
                     }

                   ]
            },
            {
                "id": "PDPA",
                "element": "switch",
                "label": "TRANSLATE.PDPA.LABEL",
                "description": "TRANSLATE.PDPA.DESC",
                "doc": "TRANSLATE.PDPA.DOC",
                "value": false
            },
            {
                "id": "StartUp",
                "element": "switch",
                "label": "TRANSLATE.STARTUP.LABEL",
                "description": "TRANSLATE.STARTUP.DESC",
                "doc": "TRANSLATE.STARTUP.DOC",
                "value": false
            }
     
        ]
   }
    ]
}


strings_en.json
Code: Select all
{
    "PLUGIN_CONFIGURATION":"Example Plugin Configuration",
    "SAVE":"Save",
    "FMXMTR":{
        "LABEL":"Configure I2C FM Transmitter module by Elechouse",
        "DESC":"Settings"
        },
    "I2CBUS":{
        "LABEL":"I2C BUS",
        "DESC":"Select I2C bus. Options 0 or 1. Default = 1",
        "DOC":"Selects which I2C bus Transmitter Module is attach to"
        },
    "I2CADDRESS":{
        "LABEL":"I2C Address 0x",
        "DESC":"Select I2C address of Module. Enter in Hex. Default = 3E",
        "DOC":"Selects I2C address on bus selected above for module. Default = 3E"
        },
    "FREQ":{
        "LABEL":"FM Channel",
        "DESC":"Enter the desired FM channel.  Default = 94.5",
        "DOC":"Selects transmission frequency. Range of transmitter is 70.1Mhz to 107.9.0Mhz in .2Mhz steps.  US FM band range is 88.0Mhz to 108.0Mhz. Default = 94.5"
        },
    "BASEBOOST":{
        "LABEL":"Base Boost",
        "DESC":"Amplify audio base frequencies. Default = 0 (0db)",
        "DOC":"Amplify audio base frequencies. Options 0, 5, 11 and 17db. Default = 0db"
        },
    "RFGAIN":{
        "LABEL":"RF Gain",
        "DESC":"Select transmitter output power level. Default = 15 (108 dBuV)",
        "DOC":"Select transmitter output power level. Options 0 - 95.5 dBuV (.071 milliwatts) to 15 - 108 dBuV (1.3 milliwatts) in 15 increments. Default = 15 (108 dBuV)"
        },
    "MUTE":{
        "LABEL":"Mute Audio",
        "DESC":"Mute audio output",
        "DOC":"Silences audio output.  Still transmitting, but channel is silent."
        },
    "MONO":{
        "LABEL":"Mono Audio",
        "DESC":"Selects Mono or Stereo audio mode.  Default = Off (Stereo mode)",
        "DOC":"Selects Mono or Stereo audio mode.  On = Mono, Off = Stereo. Default = Off (Stereo mode)"
        },
    "PGAMOD":{
        "LABEL":"PGA Mode",
        "DESC":"Select Programmable Amplifier mode. Default = 0 (4db-increments).  Must save and exit config screen to change mode.",
        "DOC":"Select Programmable Amplifier mode. 1db or 4db increments.  Default = 0 (4db-increments).  Must save and exit config screen to change mode."
        },
    "PGAMP":{
        "LABEL":"Programmable Amplifier",
        "DESC":"Programmable Amplifier acts as a volume control for the transmitter.  Default = 0 (no change to audio volume)",
        "DOC":"Programmable Amplifier acts as a volume control for the transmitter. PGAMod = 0 (Range is -15 to +15 in increments of 5).  PGAMod = 1 (Range is -15 to +15 in increments of 1). Default = 0 (no change to audio volume)"
        },
    "PLTADJ":{
        "LABEL":"Pilot Tone Adjust",
        "DESC":"Select Pilot Tone signal strength. Default = 0 (Low)",
        "DOC":"In FM stereo broadcasting, a pilot tone of 19 kHz indicates that there is stereophonic information at 38 kHz (19×2, the second harmonic of the pilot). The receiver doubles the frequency of the pilot tone and uses it as a frequency and phase reference to demodulate the stereo information.  Range is 1 (high) or 0 (low).  Default = 0 (Low)"
        },
    "PHTCNST":{
        "LABEL":"Pre-emphasis Time-Constant Set.",
        "DESC":"Select Pre-emphasis Time-Constant Set timing. Default = 0 (75 µs US)",
        "DOC":"In most of the world a 50 µs time constant is used. In the Americas, Japan and South Korea, 75 µs is used.  Range is 0 (75 µs) or 1 (50 µs) .  Default = 0 (75 µs US)."
        },
    "PDPA":{
        "LABEL":"Power Amplifier Power Down",
        "DESC":"Power Amplifier Power Down, disable RF output.  Default = Off",
        "DOC":"Power Amplifier Power Down, disable RF output.  On = shuts down transmitter.  Off = turns on transmitter, Default = Off."
        },
    "STARTUP":{
        "LABEL":"Transmit on Volumio start up",
        "DESC":"Begin transmitting immediately after Volumio starts.  Default = Off",
        "DOC":"Begin transmitting immediately after Volumio starts.  If off you must save settings from here to start broadcasting.  Off = Do not transmit.  On = Transmit.  Default = Off."
        }

    }


Enjoy,
Randy
Random avatar
Randy
Sunday DIYer
Sunday DIYer
 
Posts: 17
Joined: Fri Mar 02 2018 01:14
Location: Chesapeake, VA

Ads helps Volumio remain Free and Open Source. Please consider donating to help us continue to serve you.


Turn your Volumio Pi into a FM radio station

Postby Randy » Mon Apr 30 2018 13:12

Greetings,
Had to make a couple of fixes. It wasn't creating the config file on a fresh install, had some permission issues and it required the full path to I2C tools.

See below.

install.sh
Code: Select all
#!/bin/bash

echo "Installing fmxmtr Dependencies"
sudo apt-get update
# Install the required packages via apt-get

echo "Installing I2C-tools"
sudo apt-get -y install i2c-tools --no-install-recommends

echo "Installing base functionality for working with a Raspberry Pi from Node.js "
npm install kew v-conf fs-extra shelljs --no-install-recommends

echo "Creating default configuration file"
mkdir /data/configuration/miscellanea/fmxmtr
echo '{' > /data/configuration/miscellanea/fmxmtr/config.json
echo '    "I2C_BUS": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "1"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "I2C_ADDRESS": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "text",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "3e"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "Freq": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "94.5"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "BaseBoost": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "0"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "RFGain": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "15"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "MuteAudio": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "boolean",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": false' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "MonoAudio": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "boolean",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": false' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "PGAMod": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "0"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "PGAmp": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "0"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "PltAdj": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "0"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "PhTCnst": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "number",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": "0"' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "PDPA": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "boolean",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": false' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  },' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "StartUp": {' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "type": "boolean",' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '    "value": false' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '  }' >> /data/configuration/miscellanea/fmxmtr/config.json
echo '}' >> /data/configuration/miscellanea/fmxmtr/config.json
chown -R volumio:volumio /data/configuration/miscellanea/fmxmtr


# If you need to differentiate install for armhf and i386 you can get the variable like this
#DPKG_ARCH=`dpkg --print-architecture`
# Then use it to differentiate your install

#requred to end the plugin install
echo "plugininstallend"


index.js
Code: Select all
'use strict';

var libQ = require('kew');
var fs=require('fs-extra');
var config = new (require('v-conf'))();
var exec = require('child_process').exec;
var execSync = require('child_process').execSync;

var shell = require('shelljs');

// Create ShellCommand variable.  It is used in several functions
var ShellCommand = '';

// Define variables to hold register values read from transmitter module
var Reg0x00 = 0;
var Reg0x01 = 0;
var Reg0x02 = 0;
var Reg0x04 = 0;
var Reg0x0B = 0;
var Reg0x10 = 0;
var Reg0x12 = 0;
var Reg0x13 = 0;

// Define variables for decoded register values
var FreqRead = 0;
var BaseBoostRead = 0;
var RFGainRead = 0;
var MuteAudioRead = 0;
var MonoAudioRead = 0;
var PGAModRead = 0;
var PGAmpRead = 0;
var PltAdjRead = 0;
var PhTCnStRead = 0;
var PDPARead = false;

// Define variables for data read from conf.json
var FreqStored=0;
var BaseBoostStored=0;
var RFGainStored=0;
var MuteAudioStored=false;
var MonoAudioStored=false;
var PGAModStored=0;
var PGAmpStored=0;
var PltAdjStored=0;
var PhTCnstStored=0;
var PDPAStored=false;
var StartUpStored=false;




module.exports = Controllerfmxmtr;
function Controllerfmxmtr(context) {
   var self = this;

   this.context = context;
   this.commandRouter = this.context.coreCommand;
   this.logger = this.context.logger;
   this.configManager = this.context.configManager;

}


Controllerfmxmtr.prototype.onVolumioStart = function()
{
   var self = this;
   var configFile=this.commandRouter.pluginManager.getConfigurationFile(this.context,'config.json');
   this.config = new (require('v-conf'))();
   this.config.loadFile(configFile);

// check to see if config.json exists
    var checkfile = ("/bin/cp " + configFile + " /tmp/config.txt");
    var exists = false;
    try {
   var cp3 = execSync(checkfile);
   exists = true;
   } catch (err) {
   self.logger.info('fmxmtr config.json does not exist');
   exists = false;
   }

    if(exists){
// Disable broadcasting.  a.k.a. Airplane mode
    ShellCommand = '/usr/sbin/i2cset -y ' + this.config.get('I2C_BUS') + ' 0x' + this.config.get('I2C_ADDRESS') + ' 0x0B 0x20';
    shell.exec(ShellCommand);
    self.logger.info('Disabled RF output');

// Config.json exists, read user configuration from config.json and write to transmitter module
// I2C_BUS
        var I2CBusSave = this.config.get('I2C_BUS');
// I2C_ADDRESS
        var I2CAddressSave = this.config.get('I2C_ADDRESS');
// Freq
        var FreqSave = this.config.get('Freq');
        FreqSave = (FreqSave * 1000)/50;
// Convert config.json values to register values
// Frequency is 12 bits divided over three registers
// Register 0x02 bit 0x07 = Freq bit 0x01
// Register 0x00 bits 0x07 to 0x00 = Freq bits 0x08 to 0x01
// Register 0x01 bits 0x02 to 0x00 = Freq bits 0x11 to 0x09
// Split Freq into three registers
        var Reg0x02Freq = (FreqSave & 0x0001) *8;
        var Reg0x00Freq = (FreqSave / 2) & 0x00ff;
        var Reg0x01Freq = ((FreqSave & 0x0600) / 512);
// BaseBoost
        var BaseBoostSave = this.config.get('BaseBoost');
// BaseBoost is two bits in one register
// Register 0x04 bits 0x01 to 0x00 = BaseBoost bits 0x01 to 0x00
        var Reg0x04BaseBoost = (BaseBoostSave & 0x03);
// RFGain
        var RFGainSave = this.config.get('RFGain');
// RFGain is 4 bits divided over tthree registers
// Register 0x02 bit 0x06 = RFGain bit 0x03
// Register 0x13 bit 0x07 = RFGain bit 0x02
// Register 0x01 bits 0x07 to 0x06 - RFGain bits 0x01 to 0x00
        var Reg0x02FRGain = (RFGainSave & 0x08) * 8;
        var Reg0x13FRGain = (RFGainSave & 0x04) * 32;
        var Reg0x01FRGain = (RFGainSave & 0x03) * 64;
// MuteAudio
        var MuteAudioSave = this.config.get('MuteAudio');
// MuteAudio is one bit in one register
// Register 0x02 bit 0x03 = MuteAudio logic state
        var Reg0x02MuteAudio = 0x00;
        if (MuteAudioSave){
            Reg0x02MuteAudio = 0x08;
        } else {
            Reg0x02MuteAudio = 0x00;
        };
// MonoAudio
        var MonoAudioSave = this.config.get('MonoAudio');
// MonoAudio is one bit in one register
// Register 0x04 bit 0x06 = MonoAudio logic state
        var Reg0x04MonoAudio = 0x00;
        if (MonoAudioSave){
            Reg0x04MonoAudio = 0x40;
        } else {
            Reg0x04MonoAudio = 0x00;
        };
// PGAMod
        var PGAModSave = this.config.get('PGAMod');
// PGAMod is three bits in one register
// Register 0x10 bit 0x00 = PGAMod bit 0x00
        var Reg0x10PGAMod = PGAModSave
// PGAmp
        var PGAmpSave = this.config.get('PGAmp');
// PGAmp is 5 bits divided over two registers
// Register 0x01 bits 0x05 to 0x03 = PGAmp bits 0x04 to 0x02
// Register 0x04 bits 0x05 to 0x04 - PGAmp bits 0x01 to 0x00
        if (PGAmpSave < 0){
                PGAmpSave = PGAmpSave * -1;
            }
            else{
                PGAmpSave = (PGAmpSave *1) + 16;
                };
        var Reg0x01PGAmp = (PGAmpSave & 0x1c) * 2;
        var Reg0x04PGAmp = (PGAmpSave & 0x03) * 16;
// PltAdj
        var PltAdjSave = this.config.get('PltAdj');
// PltAdj is one bit in one register
// Register 0x02 bit 0x02 = PltAdj bit 0x00
        var Reg0x02PltAdj = (PltAdjSave & 0x01) * 4;
// PhTCnst
        var PhTCnstSave = this.config.get('PhTCnst');
// PhTCnst is one bit in one register
// Register 0x02 bit 0x00 = PhTCnst bit 0x00
        var Reg0x02PhTCnst = (PhTCnstSave & 0x01);
// PDPA
        var PDPASave = this.config.get('PDPA');
// PDPA is one bit in one register
// Register 0x0B bit 0x05 = PDPA logic state
        var Reg0x0BPDPA = 0x00;
        if (PDPASave){
            Reg0x0BPDPA = 0x20;
        } else {
            Reg0x0BPDPA = 0x00;
        };
// combine all bit per register
// Register 0x00 is made up of Reg0x00Freq only
        var Reg0x00Write = Reg0x00Freq;
// Register 0x01 is made up of Reg0x01FRGain, Reg0x01PGAmp and Reg0x01Freq
        var Reg0x01Write = (Reg0x01FRGain + Reg0x01PGAmp + Reg0x01Freq);
//Register 0x02 is made up of Reg0x02Freq, Reg0x02FRGain, Reg0x02MuteAudio, Reg0x02PltAdj and Reg0x02PhTCnst
        var Reg0x02Write = (Reg0x02 & 0x32) + (Reg0x02Freq + Reg0x02FRGain + Reg0x02MuteAudio + Reg0x02PltAdj + Reg0x02PhTCnst);
// Register 0x04 is made up of Reg0x04MonoAudio, Reg0x04PGAmp and Reg0x04BaseBoost
        var Reg0x04Write = (Reg0x04 & 0x8c) + (Reg0x04MonoAudio + Reg0x04PGAmp + Reg0x04BaseBoost);
// Register 0x0b is made up of Reg0x0BPDPA only
        var Reg0x0BWrite = (Reg0x0B & 0xdf) + Reg0x0BPDPA;
// Register 0x10 is made up of Reg0x10PGAMod only
        var Reg0x10Write = (Reg0x10 & 0xfe) + Reg0x10PGAMod;
// Register 0x13 is made up of  only Reg0x13FRGain
        var Reg0x13Write = (Reg0x13 & 0x7f) + Reg0x13FRGain;
// Write registers
        ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x00 0x' + Reg0x00Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x01 0x' + Reg0x01Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x02 0x' + Reg0x02Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x04 0x' + Reg0x04Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x0B 0x' + Reg0x0BWrite.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x10 0x' + Reg0x10Write.toString(16);
        shell.exec(ShellCommand);
        ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x13 0x' + Reg0x13Write.toString(16);
        shell.exec(ShellCommand);

// Check to see if user desires to start transmitting on Volumio Start
        if (this.config.get('StartUp')){
            ShellCommand = '/usr/sbin/i2cset -y ' + this.config.get('I2C_BUS') + ' 0x' + this.config.get('I2C_ADDRESS') + ' 0x0B 0x00';
            shell.exec(ShellCommand);
        }
        else
        {
            ShellCommand = '/usr/sbin/i2cset -y ' + this.config.get('I2C_BUS') + ' 0x' + this.config.get('I2C_ADDRESS') + ' 0x0B 0x20';
            shell.exec(ShellCommand);
        };
    }
    else {
// config.json does not exist, create it, fill with defaults and write defaults to registers on transmitter module
// Disable broadcasting using default values.  a.k.a. Airplane mode
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x0B 0x20');
        self.logger.info('Disabled RF output');

// Create file
        ShellCommand = ('mkdir /data/configuration/miscellanea/fmxmtr');
        shell.exec(ShellCommand);
        ShellCommand = ('echo {} > ' + configFile);
        shell.exec(ShellCommand);
        self.logger.info('Created fmxmtr config.json');

// Fill it with default values
        self.config.set('I2C_BUS',1);
        self.config.set('I2C_ADDRESS',"3e");
        self.config.set('Freq',"94.5");
        self.config.set('BaseBoost',0);
        self.config.set('RFGain',15);
        self.config.set('MuteAudio',false);
        self.config.set('MonoAudio',false);
        self.config.set('PGAMod',0);
        self.config.set('PGAmp',0);
        self.config.set('PltAdj',0);
        self.config.set('PhTCnst',0);
        self.config.set('PDPA',false);
        self.config.set('StartUp',true);

// Set default values on transmiter module
    // Write default registers
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x00 0xb1');
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x01 0xe3');
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x02 0x40');
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x04 0x04');
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x0b 0x00');
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x10 0xa8');
        shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x13 0x80');
    };

    return libQ.resolve();
}

Controllerfmxmtr.prototype.onStart = function() {
    var self = this;
   var defer=libQ.defer();


// Read registers starting values from module
    Reg0x00 = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x00');
    Reg0x01 = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x01');
    Reg0x02 = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x02');
    Reg0x04 = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x04');
    Reg0x0B = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x0B');
    Reg0x10 = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x10');
    Reg0x12 = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x12');
    Reg0x13 = shell.exec('/usr/sbin/i2cget -y 1 0x3e 0x13');

// Decode registers into working values
    FreqRead = ((Reg0x01 & 0x07) * 512) + (Reg0x00 * 2) + ((Reg0x02 & 0x80)/128);
    BaseBoostRead = (Reg0x04 & 0x03);
    RFGainRead = ((Reg0x02 & 0x40)/8) + ((Reg0x13 & 0x80)/32) + ((Reg0x01 & 0xc0)/64);
    MuteAudioRead = ((Reg0x02 & 0x08)/8);
    MonoAudioRead = ((Reg0x04 & 0x40)/64);
    PGAModRead = (Reg0x10 & 1);
    PGAmpRead = ((Reg0x01 & 0x38)/2) + ((Reg0x04 & 0x30)/16);
    PltAdjRead = ((Reg0x02 & 0x04)/4);
    PhTCnStRead = (Reg0x02 & 0x01);
    PDPARead = ((Reg0x0B & 0x20)/32);


// Once the Plugin has successfull started resolve the promise
   defer.resolve();

    return defer.promise;
};

Controllerfmxmtr.prototype.onStop = function() {
    var self = this;
    var defer=libQ.defer();

// Once the Plugin has successfull stopped resolve the promise
    defer.resolve();

    return libQ.resolve();
};

Controllerfmxmtr.prototype.onRestart = function() {
    var self = this;
// Optional, use if you need it


};


// Configuration Methods -----------------------------------------------------------------------------

Controllerfmxmtr.prototype.getUIConfig = function() {
    var defer = libQ.defer();
    var self = this;

    var lang_code = this.commandRouter.sharedVars.get('language_code');

    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('I2C_BUS');
                uiconf.sections[0].content[0].value.label = self.config.get('I2C_BUS');
                uiconf.sections[0].content[1].value = self.config.get('I2C_ADDRESS');
                uiconf.sections[0].content[2].config.bars[0].value = self.config.get('Freq');
                uiconf.sections[0].content[3].value.value = self.config.get('BaseBoost');
                uiconf.sections[0].content[3].value.label = self.config.get('BaseBoost');
                uiconf.sections[0].content[4].value.value = self.config.get('RFGain');
                uiconf.sections[0].content[4].value.label = self.config.get('RFGain');
                uiconf.sections[0].content[5].value = self.config.get('MuteAudio');
                uiconf.sections[0].content[6].value = self.config.get('MonoAudio');
                uiconf.sections[0].content[7].value.value = self.config.get('PGAMod');
                uiconf.sections[0].content[7].value.label = self.config.get('PGAMod');
                if (self.config.get('PGAMod') == 0) {
                    uiconf.sections[0].content[8].config.bars[0].value = (self.config.get('PGAmp') - (self.config.get('PGAmp') % 5));
                    uiconf.sections[0].content[8].config.bars[0].step = 5;
                } else {
                    uiconf.sections[0].content[8].config.bars[0].step = 1;
                    uiconf.sections[0].content[8].config.bars[0].value = self.config.get('PGAmp');
                };
                uiconf.sections[0].content[9].value.value = self.config.get('PltAdj');
                uiconf.sections[0].content[9].value.label = self.config.get('PltAdj');
                uiconf.sections[0].content[10].value.value = self.config.get('PhTCnst');
                uiconf.sections[0].content[10].value.label = self.config.get('PhTCnst');
                uiconf.sections[0].content[11].value = self.config.get('PDPA');
                uiconf.sections[0].content[12].value = self.config.get('StartUp');
                   
                defer.resolve(uiconf);
            }
        )
    .fail(function()
        {
            defer.reject(new Error());
        }
    );

return defer.promise;
};


Controllerfmxmtr.prototype.setUIConfig = function(data) {
   var self = this;
   //Perform your installation tasks here

};

Controllerfmxmtr.prototype.getConf = function(varName) {
   var self = this;
//Perform your installation tasks here
};

Controllerfmxmtr.prototype.setConf = function(varName, varValue) {
   var self = this;
//Perform your installation tasks here
};

// define what happens when the user clicks the 'save' button on the settings page
// save new values and write them to the transmitter module
Controllerfmxmtr.prototype.SaveFMXmtrOptions = function(data) {
    var self = this;
    var successful = true;

// Save I2C_BUS
    var I2CBusSave = data.I2C_BUS.value;
    self.config.set('I2C_BUS',I2CBusSave);
   
// Save I2C_ADDRESS
    var I2CAddressSave = data.I2C_ADDRESS;
    self.config.set('I2C_ADDRESS',I2CAddressSave);

// Save Freq
    var FreqSave = data.Freq;
    self.config.set('Freq',FreqSave);
    FreqSave = (FreqSave * 1000)/50;

// Convert save values to register values
// Frequency is 12 bits divided over three registers
// Register 0x02 bit 0x07 = Freq bit 0x01
// Register 0x00 bits 0x07 to 0x00 = Freq bits 0x08 to 0x01
// Register 0x01 bits 0x02 to 0x00 = Freq bits 0x11 to 0x09
// Split Freq into three registers
    var Reg0x02Freq = (FreqSave & 0x0001) *8;
    var Reg0x00Freq = (FreqSave / 2) & 0x00ff;
    var Reg0x01Freq = ((FreqSave & 0x0600) / 512);
   
// Save BaseBoost
    var BaseBoostSave = data.BaseBoost.value;
    self.config.set('BaseBoost',BaseBoostSave);
   
// Convert save values to register values
// BaseBoost is two bits in one register
// Register 0x04 bits 0x01 to 0x00 = BaseBoost bits 0x01 to 0x00
    var Reg0x04BaseBoost = (BaseBoostSave & 0x03);

// Save RFGain
    var RFGainSave = data.RFGain.value;
    self.config.set('RFGain',RFGainSave);

// Convert save values to register values
// RFGain is 4 bits divided over tthree registers
// Register 0x02 bit 0x06 = RFGain bit 0x03
// Register 0x13 bit 0x07 = RFGain bit 0x02
// Register 0x01 bits 0x07 to 0x06 - RFGain bits 0x01 to 0x00
    var Reg0x02FRGain = (RFGainSave & 0x08) * 8;
    var Reg0x13FRGain = (RFGainSave & 0x04) * 32;
    var Reg0x01FRGain = (RFGainSave & 0x03) * 64;

// Save MuteAudio
    var MuteAudioSave = data.MuteAudio;
    self.config.set('MuteAudio',MuteAudioSave);

// Convert save values to register values
// MuteAudio is one bit in one register
// Register 0x02 bit 0x03 = MuteAudio logic state
    var Reg0x02MuteAudio = 0x00;
    if (MuteAudioSave){
        Reg0x02MuteAudio = 0x08;
    } else {
        Reg0x02MuteAudio = 0x00;
    };

// Save MonoAudio
    var MonoAudioSave = data.MonoAudio;
    self.config.set('MonoAudio',MonoAudioSave);

// Convert save values to register values
// MonoAudio is one bit in one register
// Register 0x04 bit 0x06 = MonoAudio logic state
    var Reg0x04MonoAudio = 0x00;
    if (MonoAudioSave){
        Reg0x04MonoAudio = 0x40;
    } else {
        Reg0x04MonoAudio = 0x00;
    };

// Save PGAMod
    var PGAModSave = data.PGAMod.value;
    self.config.set('PGAMod',PGAModSave);

// Convert save values to register values
// PGAMod is three bits in one register
// Register 0x10 bit 0x00 = PGAMod bit 0x00
    var Reg0x10PGAMod = PGAModSave

// Save PGAmp
    var PGAmpSave = data.PGAmp;
    self.config.set('PGAmp',PGAmpSave);

// Convert save values to register values
// PGAmp is 5 bits divided over two registers
// Register 0x01 bits 0x05 to 0x03 = PGAmp bits 0x04 to 0x02
// Register 0x04 bits 0x05 to 0x04 - PGAmp bits 0x01 to 0x00
    if (PGAmpSave < 0){
            PGAmpSave = PGAmpSave * -1;
        }
        else{
            PGAmpSave = (PGAmpSave *1) + 16;
            };
    var Reg0x01PGAmp = (PGAmpSave & 0x1c) * 2;
    var Reg0x04PGAmp = (PGAmpSave & 0x03) * 16;

// Save PltAdj
    var PltAdjSave = data.PltAdj.value;
    self.config.set('PltAdj',PltAdjSave);

// Convert save values to register values
// PltAdj is one bit in one register
// Register 0x02 bit 0x02 = PltAdj bit 0x00
     var Reg0x02PltAdj = (PltAdjSave & 0x01) * 4;

// Save PhTCnst
    var PhTCnstSave = data.PhTCnst.value;
    self.config.set('PhTCnst',PhTCnstSave);

// Convert save values to register values
// PhTCnst is one bit in one register
// Register 0x02 bit 0x00 = PhTCnst bit 0x00
    var Reg0x02PhTCnst = (PhTCnstSave & 0x01);

// Save PDPA
    var PDPASave = data.PDPA;
    self.config.set('PDPA',PDPASave);

// Save StartUp
    var StartUpSave = data.StartUp;
    self.config.set('StartUp',StartUpSave);

// Convert save values to register values
// PDPA is one bit in one register
// Register 0x0B bit 0x05 = PDPA logic state
    var Reg0x0BPDPA = 0x00;
    if (PDPASave){
        Reg0x0BPDPA = 0x20;
    } else {
        Reg0x0BPDPA = 0x00;
    };

// combine all bit per register
// Register 0x00 is made up of Reg0x00Freq only
    var Reg0x00Write = Reg0x00Freq;
// Register 0x01 is made up of Reg0x01FRGain, Reg0x01PGAmp and Reg0x01Freq
    var Reg0x01Write = (Reg0x01FRGain + Reg0x01PGAmp + Reg0x01Freq);
//Register 0x02 is made up of Reg0x02Freq, Reg0x02FRGain, Reg0x02MuteAudio, Reg0x02PltAdj and Reg0x02PhTCnst
    var Reg0x02Write = (Reg0x02 & 0x32) + (Reg0x02Freq + Reg0x02FRGain + Reg0x02MuteAudio + Reg0x02PltAdj + Reg0x02PhTCnst);
// Register 0x04 is made up of Reg0x04MonoAudio, Reg0x04PGAmp and Reg0x04BaseBoost
    var Reg0x04Write = (Reg0x04 & 0x8c) + (Reg0x04MonoAudio + Reg0x04PGAmp + Reg0x04BaseBoost);
// Register 0x0b is made up of Reg0x0BPDPA only
    var Reg0x0BWrite = (Reg0x0B & 0xdf) + Reg0x0BPDPA;
// Register 0x10 is made up of Reg0x10PGAMod only
    var Reg0x10Write = (Reg0x10 & 0xfe) + Reg0x10PGAMod;
// Register 0x13 is made up of  only Reg0x13FRGain
    var Reg0x13Write = (Reg0x13 & 0x7f) + Reg0x13FRGain;
// Write registers
    //shell.exec('/usr/sbin/i2cset -y 1 0x3e 0x00 0x00');
    ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x00 0x' + Reg0x00Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x01 0x' + Reg0x01Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x02 0x' + Reg0x02Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x04 0x' + Reg0x04Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x0B 0x' + Reg0x0BWrite.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x10 0x' + Reg0x10Write.toString(16);
    shell.exec(ShellCommand);
    ShellCommand = '/usr/sbin/i2cset -y ' + I2CBusSave + ' 0x' + I2CAddressSave + ' 0x13 0x' + Reg0x13Write.toString(16);
    shell.exec(ShellCommand);
};


Enjoy,
Randy
Random avatar
Randy
Sunday DIYer
Sunday DIYer
 
Posts: 17
Joined: Fri Mar 02 2018 01:14
Location: Chesapeake, VA


Turn your Volumio Pi into a FM radio station

Postby Josh2000 » Tue May 01 2018 14:25

Hi Randy,

Great idea.

Could you please provide a zip file containing the content on github ?
I'd like to try but i'm not aware of how to copy all the stuff.

Thank you.

Josef
User avatar
Josh2000
Audiophile
Audiophile
 
Posts: 147
Joined: Mon Oct 17 2016 16:43


Turn your Volumio Pi into a FM radio station

Postby Randy » Sun May 06 2018 21:26

Josh,
Sorry to take so long to respond. Been busy at work.

I can email the zip file to you. Just need an address.

Is there a way to attach it to a message here?

You could also try opening a console on the Volumio Pi or SSH into it and enter the commands below.

volumio plugin init
cd volumio-plugins/plugins/miscellanea/fmxmtr
volumio plugin install

That should do it. It will tell you to do "Volumio plugin init" again, but it is not required. The first time should download all the available plugins into the volumio home folder under volumio-plugins. Under that are the different categories. This one will be under miscellanea in the folder fmxmtr. Do "volumio plugin install" from within this directory to install it.

Good luck,
Randy
Random avatar
Randy
Sunday DIYer
Sunday DIYer
 
Posts: 17
Joined: Fri Mar 02 2018 01:14
Location: Chesapeake, VA


Turn your Volumio Pi into a FM radio station

Postby Josh2000 » Wed Jun 13 2018 18:17

Hi Randy,

Sorry for also took so long to answer.

After i got it managed to get the 1.02 version downloaded everythink worked perfect.

The only thing is the sound get's distorted. I decreased the line level to about 200mV - it gets more quiet but still distorts the signal.
It's a little bit better if i switch to mono.
I ordered another sender module now in hope the one i got is damaged.

Anyway this has nothing to do with your plugin which is working perfect.
Thank you a lot.

Josef
User avatar
Josh2000
Audiophile
Audiophile
 
Posts: 147
Joined: Mon Oct 17 2016 16:43


Turn your Volumio Pi into a FM radio station

Postby Josh2000 » Fri Jun 22 2018 21:31

Hi Randy,

I just want to let you know that the distortion is gone with the new module i got last week. :D :D :D

- Josef.
User avatar
Josh2000
Audiophile
Audiophile
 
Posts: 147
Joined: Mon Oct 17 2016 16:43


Return to Diy Volumio Projects

Who is online

Users browsing this forum: No registered users and 6 guests