Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Outsmarting the smart meter (Jfokus 2017)

230 views

Published on

Starting 2014, all Dutch households will receive a “smart meter” to replace their old meter systems for electricity and gas. They’re called “smart”, but are they really? Most meters just send their data to a central point using GPRS. Using third party services, consumers can get an insight in their energy usage.

But we’re technicians, we can build something better ourselves. All it takes is a prefab cable (or some soldering), code, patience and a beer. Using Scala plus Akka for the backend, ES6 plus React for the frontend and Websockets for communication you can build your own energy dashboard. In this session we’ll discover how to outsmart the Smart Meter!

Published in: Software
  • Be the first to comment

  • Be the first to like this

Outsmarting the smart meter (Jfokus 2017)

  1. 1. Outsmarting the Smart Meter Jfokus // February 8, 2016 Maarten Mulders // @mthmulders
  2. 2. What's Up? Background Connecting the Smart Meter Building a Dashboard Questions
  3. 3.  
  4. 4.  
  5. 5.   Connecting the Smart Meter Pin # Signal name Description 1 +5 V Power supply 2 Request Input 3 Data GND Ground 4 not connected 5 Data Output 6 Power GND Power supply
  6. 6. Reading data $ cu -l /dev/ttyUSB0 -s 115200 --parity=none Connected. /KFM5KAIFA-METER 1-3:0.2.8(42) 0-0:1.0.0(160416112854S) ... ... !4016 ~. Disconnected.
  7. 7. Interpreting data identi cation: vendor-speci c, not speci ed data: CRC16-checksum over / to ! /???5<identification> <data> (repeated) !<CRC> OBIS-reference(value)
  8. 8. Parsing data This is easily parsed with Scala's parser combinators   Input: Parser: 000635.311 def number = """d*.?d*""".r ^^ { BigDecimal(_) }
  9. 9. Parsing data (ctd) This is easily parsed with Scala's parser combinators   Input: Parser: 1-0:1.8.1(000635.311*kWh) def elecCons1 = "1-0:1.8.1(" ~> """d*.?d*""".r <~ "*kWh)" ^^ { BigDecimal(_) }
  10. 10. Parsing data (ctd) This is easily parsed with Scala's parser combinators def make = "/" ~> "[A-Za-z0-9]{3}".r ^^ { String(_) } def identification = "5" ~> ".*".r ^^ { String(_) } def header = make ~ identification ^^ { case make ~ identification => P1Header(make, identification) }
  11. 11. Parsing data (ctd) This is easily parsed with Scala's parser combinators private def telegram = header ~ metadata ~ data ~ checksum private def parser: Parser[P1Telegram] = telegram ^^ { case header ~ metadata ~ data ~ checksum => P1Telegram(header, metadata, data, checksum) } | failure("Not all required lines are found")
  12. 12. Architecture Smart Meter Hyperion raw data Database historical records Client (web) live data & historical records
  13. 13. Hyperion (1) Collecting Actor   #append(...) P1 Parser   #parseTelegram()   Message Distributor   TelegramReceived    (telegram) IO(Serial)    Serial.Received (bytes)
  14. 14. Hyperion (2) Client (Browser) IO(UHttp)   HTTP & WebSockets RecentHistoryActor    GetRecentHistory     RecentReadings ActualValuesHandlerActor    HandshakeRequest     UpgradeServer TextFrame DailyHistoryActor     RetrieveMeterReading      RetrievedMeterReading    StateTimeout    Message Distributor     RegisterReceiver      TelegramReceived (telegram)     RegisterReceiver      TelegramReceived (telegram)     RegisterReceiver      TelegramReceived (telegram)
  15. 15. Web Dashboard Separate ui and data Single page app Small components (UI and logic)
  16. 16. ES6 classes class CurrentReadingsService { constructor() { const hostname = config.apiLocation(); this.base_url = `wss://${hostname}/api/actual`; } connect(cb) { this.ws = new WebSocket(this.base_url); this.ws.onmessage = (message) => cb(JSON.parse(message.data)); } disconnect() { this.ws.close(); } } export default new CurrentReadingsService();
  17. 17. React Components (1) class CurrentReadingsPage extends React.Component { componentDidMount() { currentReadingsService.connect((data) => { this.setState({ currentReading: data, }); }); } componentWillUnmount() { currentReadingsService.disconnect(); } // continued... }
  18. 18. React Components (2) class CurrentReadingsPage extends React.Component { // continued... render() { const makeRow = (label, value) => (<Row> <Col lg={ 6 }><strong>{ label }</strong></Col> <Col lg={ 6 }>{ value }</Col> </Row>); return (<Grid> { makeRow("Last updated", formattingService.formatDateFull(ts)) } { makeRow("Electricity consumption", formattingService.formatNumberPower(consumption)) } { makeRow("Electricity production", formattingService.formatNumberPower(production)) } { gas ? makeRow("Gas meter", formattingService.formatNumberGas(gas)) : null } { makeRow("Current tariff", tariff) } </Grid>); } }
  19. 19. Web Dashboard
  20. 20. What's Going On? (1)
  21. 21. What's Going On? (1)
  22. 22. What's Going On? (2)
  23. 23. What's Going On? (2)
  24. 24. Questions?

×