Espruino:Примеры/Самодельный смарт-счетчик электроэнергии

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Самодельный смарт-счетчик электроэнергии[1]

DIY Smart Electricity Meter with Puck.js

Почти у всех цифровых счетчиков электроэнергии (с приставкой «смарт» или без нее) есть световой индикатор, который мигает при каждом использовании определенного объема электроэнергии – часто один раз за использованный ватт-час. Обычно рядом с этим индикатором есть надпись вроде «1000 imp/kWh»).

Мигание этого индикатора можно определять светочувствительным резистором, а значит – использовать это для измерения и записи данных о динамике энергопотребления.

Вам понадобятся

Подключение

Просто припаяйте светочувствительный резистор между контактами D1 и D2, чтобы его головка торчала из отверстия в задней части корпуса Puck.js.

Более подробно смотрите на видео выше.

Простой счетчик импульсов

Код, используемый в видео, считывает количество импульсов и рассылает эту информацию с помощью BLE-объявлений.

Просто скопируйте и вставьте его в правую часть онлайн-IDE и нажмите на кнопку загрузки.

var counter = 0;

// Обновляем содержимое BLE-объявлений. 
function update() {
  var a = new ArrayBuffer(4);
  var d = new DataView(a);
  d.setUint32(0, counter, false/*от старшего к младшему*/);
  NRF.setAdvertising({},{
    name: "Puck.js \xE2\x9A\xA1",
    manufacturer:0x0590,
    manufacturerData:a,
    interval: 600 // по умолчанию 375,
                  // позволяет немного сэкономить энергию
  });
}

// Задаем состояния контактов.
D1.write(0);
pinMode(D2,"input_pullup");
// Следим, как меняются состояния контактов.
setWatch(function(e) {
 counter++;
 update();
 digitalPulse(LED1,1,1); // показываем активность
}, D2, { repeat:true, edge:"falling" });

Счетчик импульсов с записью данных о динамике энергопотребления

Мы можем пойти ещё дальше, сохраняя данные о динамике энергопотребления на сам Puck.js.

В коде ниже используется тот же код для обнаружения световых импульсов, как и в примере выше, но в него также добавлен класс Counter, в котором как раз и будут храниться данные о динамике энергопотребления. После подключения к Web Bluetooth данные можно будет считывать и показывать на графике.

Чтобы этот код заработал:

  • Зайдите в настройки онлайн-IDE (иконка с шестеренкой справа вверху), затем кликните на Communications и убедитесь, что у вас стоит галочка рядом с пунктом Set Current Time.
  • Скопируйте и вставьте код ниже в правую часть онлайн-IDE.
  • Нажмите на кнопку загрузки.
  • Впишите save() в левой части онлайн-IDE. Теперь все готово.
/** Создаем новый счётчик, содержащий следующее:
{
  totals : {
    count // общий счетчик
    year  // месяц в году (0..11)
    week  // день недели (0..6)
    month // день месяца (0..31)
    day : // час (0..23)
  },
  history // час в последних 96 часах (0..95)
}
*/
function Counter() {
  this.clear();
};
/// Сбрасываем счетчики обратно до 0.
Counter.prototype.clear = function() {
  this.totals = {
    count : 0,                   // общий счетчик
    year : new Uint32Array(12),  // месяц в году (0..11)
    week : new Uint32Array(7),   // день в неделе (0..6)
    month : new Uint32Array(31), // день в месяце (0..31)
    day : new Uint32Array(24)    // час (0..23)
  };
  this.historyPeriod = 60*60*1000;    // 1 час в миллисекундах
  this.history = new Uint32Array(96); // последние 96 часов
  this.historyTime = 0;
  this.lastUpdate = new Date.now();
};
///
Counter.prototype.inc = function(n) {
  if (n===undefined) n=1;
  var d = new Date();
  var t = this.totals;
  // Суммарный показатель за некоторый промежуток времени.
  t.count+=n;  
  t.year[d.getMonth()]+=n;
  t.week[d.getDay()]+=n;
  t.month[d.getDate()-1]+=n;
  t.day[d.getHours()]+=n;
  // Смотрим историю.
  this.historyTime += d.getTime()-this.lastUpdate;
  this.lastUpdate = d.getTime();
  var steps = Math.floor(this.historyTime / this.historyPeriod);
  if (steps>=0) {
    this.historyTime -= steps*this.historyPeriod;
    var h = this.history;
    h.set(new Uint32Array(h.buffer, 4*steps), 0);
    h.fill(0, h.length-steps);
    h[h.length-1]+=n;
  }
};
var c = new Counter();

// Обновляем содержимое BLE-объявлений.
function update() {
  var a = new ArrayBuffer(4);
  var d = new DataView(a);
  d.setUint32(0, c.totals.count, false/*от старшего к младшему*/);
  NRF.setAdvertising({},{
    name: "Puck.js \xE2\x9A\xA1",
    manufacturer:0x0590,
    manufacturerData:a,
    interval: 600 // по умолчанию 375,
                  // позволяет немного сэкономить энергию
  });
}

function onInit() {
  clearWatch();
  D1.write(0);
  pinMode(D2,"input_pullup");
  setWatch(function(e) {
    c.inc(1);
    update();
    digitalPulse(LED1,1,1); // показываем активность
  }, D2, { repeat:true, edge:"falling" });
  update();
}

Теперь Puck.js настроен и мы можем воспользоваться сайтом Web Bluetooth ниже (или перед этим немного модифицировать его согласно нашим нуждам).

Чтобы попробовать его, просто нажмите на кнопку «Попробуй!» в правой нижней части под кодом. Чтобы создать собственную версию этой страницы, следуйте инструкциям по созданию GitHub-страницы в начале вот этого руководства.

<html>
 <head>
  <title>Dashboard</title>
  <meta name="viewport" content="width=620, initial-scale=1">
 </head>
 <body style="width:620px;height:800px">
  <link href="https://espruino.github.io/TinyDash/tinydash.css" rel="stylesheet">
  <script src="https://espruino.github.io/TinyDash/tinydash.js"></script>
  <script src="https://www.puck-js.com/puck.js"></script>  
  <script>
  function connectDevice() {    
    // Подключаемся и даем команду Ctrl-C,
    // чтобы стереть все данные, которые могли остаться в REPL:
    Puck.write("\x03", function() {
      setTimeout(function() {
        // После короткой задержки запрашиваем процент заряда батареи. 
        Puck.eval("{bat:E.getBattery()}", function(d,err) {
          if (!d) {
            alert("Соединение с Web Bluetooth потеряно!\n"+(err||""));
            return;
          }
          // Удаляем окно 'connect'
          elements.modal.remove();
          // Обновляем информацию о заряде батареи.
          elements.bat.setValue(d.bat);
          // Считываем все наши данные. 
          // Это может занять некоторое время, 
          // так что делаем это в несколько этапов.
          Puck.eval("c.totals", function(d,err) {
            elements.total.setValue(d.count);
            elements.year.setData(d.year);
            elements.week.setData(d.week);
            elements.month.setData(d.month);
            elements.day.setData(d.day);
            // Считываем данные за последние 96 часов.
            Puck.eval("c.history", function(d) {
              elements.history.setData(d);
            });
          });
        }, 500);
      });
    });
  }
  // Настраиваем средства управления, 
  // которые будут показаны на экране.
  var elements = {
    heading : TD.label({x:10,y:10,width:190,height:50,label:"Electricity meter"}),
    total : TD.value({x:10,y:70,width:190,height:60,label:"Total Usage",value:0}),
    bat : TD.gauge({x:10,y:140,width:190,height:220,label:"Battery Level",value:0,min:0,max:100}),
    history : TD.graph({x:210,y:10+160*0,width:400,height:150,label:"96 hr history"}),
    day : TD.graph({x:210,y:10+160*1,width:400,height:150,label:"Day"}),
    month : TD.graph({x:210,y:10+160*2,width:400,height:150,label:"Month"}),
    week : TD.graph({x:210,y:10+160*3,width:400,height:150,label:"Week"}),
    year : TD.graph({x:210,y:10+160*4,width:400,height:150,label:"Year"}),
    modal: TD.modal({x:10,y:10,width:600,height:790,label:"Click to connect",onchange:connectDevice})
  }
  for (var i in elements)
    document.body.appendChild(elements[i]);
  </script>
 </body>
</html>
Примечание
  • В примере выше это не запрограммировано, но текущее энергопотребление также можно рассчитать при помощи измерения времени между импульсами – это будет хорошим дополнением к уже имеющимся данным в BLE-объявлении.
  • Сайты Web Bluetooth не умеют считывать данные объявлений (пока) и потому не могут показывать какие-либо данные об энергопотреблении без подключения. Но другие Espruino-устройства (вроде Pixl.js) это делать умеют.
  • Сопротивление светочувствительного резистора варьируется в зависимости от окружающего освещения. На стандартных светочувствительных резисторах вроде GL5537 полная темнота будет давать сопротивление около 2 МОм, что будет тянуть очень мало энергии от «таблетки», подключенной к внутреннему подтягивающему резистору на 40 кОм. Но чем интенсивнее будет окружающий свет, тем ниже будет сопротивление, а следовательно – тем быстрее будет расходоваться заряд батареи. Так что есть смысл максимально углубить резистор в отверстии Puck.js.

См.также

Внешние ссылки