Hacking a weighing scale

Last couple of weekends I mainly spent at home. This was ideal opportunity to do some home maintenance (cleaning 🙁 ). Somewhere under the bed I found a weighing scale that my wife and I occasionally use. This is the simple digital weighing scale from Ikea – GRUNDTAL. During last months I stumbled upon couple of articles about automatic weight logging, so the outcome was obvious: the next home project – wireless logging weighing scale. Luckily I already had necessary tools and parts, so the next couple of days were fun.

IKEA GRUNDTAL Weghing scale

The idea was to connect the scale to Arduino Pro Mini, decode the readings from the scale, and send the weight wirelessly, using RFM12B radio module from HopeRF, to the central Homy system. There, the weight with the timestamp would be persisted into the database and published to Facebook wall.

The excellent starting point was project SdCardBathroomScale. Other useful resources were Hacking a digital bathroom scaleDigital Scale Strain Gauge Weight Sensor, … I decided to use the simplest and the fastest approach – hooking to LCD signals, and decoding data sent to the display.

LCD display

Opening the scale was really simple; there are four screws to be unscrewed to access the inside of the scale. Then, six more screws to access the main circuit board of the scale. The nice surprise was that there were testing points for every pin going to LCD. I used these to solder “spy” cable. In addition to these, I soldered two more wires, one for GND and one for 5V, that would be used to power Arduino.

Soldering "spy" cable

After that I put the board back and fixed it with six screws. With that I finished hardware hacking part. Nice thing was that there was enough space left in the scale to put additional stuff like Arduino and wireless module.

"Spy" cable, 5V and GND

One important thing about the spy cable is to solder the wires in the same order as pins on the LCD; this will make things much easier later (I mixed up two wires, and was receiving some “crazy” numbers 🙁 ) On the picture below, I marked the pins on the LCD as A, B, C, 1, 2, …, 12.

Scale LCD pinout

The second step was to figure out how to decode the signals coming to LCD. Big help in understanding how this LCD works was a document describing LCD driver for  Z8 Encore!. After some probing, I came to the diagram that represents how LCD works in this scale and maps specific LED segment to the coresponding pin.

LCD display map

All the segments on the LCD are divided in 3 planes: A (green), B (yellow) and C (red) and 12 groups: 1, 2, …, 12. All these (planes and groups) are mapped to specific pins, and by reading signal values, it would be possible to decode the value displayed on the scale using some simple acquisition algorithm and one multiple-output boolean function.

The third step was to connect the Arduino to the LCD and to connect the wireless module to the Arduino. After some soldering and testing all the connections, everything was ready for the next step.

Arduino pinout
Arduino Pro Mini, RFM12B module and weighing scale connected

The forth step was developing the program that will run on the Arduino. There were two important parts: decoding the LCD signals and optimizing the power consumption.

For the decoding part a combination of statistical methods and boolean function was used in order to have accurate readout of the display. For the power consumption part, interrupts and low power states were used. Minimizing the power consumption was necessary in order to maximize the life of 9V battery that was used to power the scale. I managed to go down with the consumption to 100μA.

This is the final program :

#include <JeeLib.h>
#include <SoftwareSerial.h>
#include <Streaming.h>
#include <avr/sleep.h>

#define DEBUG 0
#define THIS_NODE 15
#define DEST_NODE 13

#if DEBUG
	SoftwareSerial serial(0, 1);
#endif

int lcdA=0,lcdB=0,lcdC=0;

int pa,pb,pc;
bool lcd1,lcd2,lcd3,lcd4,lcd5,lcd6,lcd7,lcd8,lcd9,lcd10,lcd11,lcd12;

unsigned int SAn, SBn, SCn;
unsigned int SA[12], SB[12], SC[12];
bool A[12], B[12], C[12];

unsigned int _t;

int getDigit(int i, int j, int k)
{
	if ( A[i] &&  A[j] &&  true &&  B[i] && !B[j] &&  true &&  C[i] &&  C[j] &&  true) return 0;
	if ( A[i] && !A[j] &&  true &&  B[i] && !B[j] &&  true && !C[i] && !C[j] &&  true) return 1;
	if ( A[i] &&  A[j] &&  true && !B[i] &&  B[j] &&  true &&  C[i] &&  C[j] &&  true) return 2;
	if ( A[i] &&  A[j] &&  true &&  B[i] &&  B[j] && !B[k] &&  C[i] && !C[j] &&  true) return 3;
	if ( A[i] && !A[j] &&  true &&  B[i] &&  B[j] &&  true && !C[i] && !C[j] &&  true) return 4;
	if (!A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  true &&  C[i] && !C[j] &&  true) return 5;
	if (!A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  true &&  C[i] &&  C[j] &&  true) return 6;
	if ( A[i] &&  A[j] &&  true &&  B[i] && !B[j] &&  true && !C[i] && !C[j] &&  true) return 7;
	if ( A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  true &&  C[i] &&  C[j] &&  true) return 8;
	if ( A[i] &&  A[j] &&  true &&  B[i] &&  B[j] &&  B[k] &&  C[i] && !C[j] &&  true) return 9;
	return 0;
}

void wakeUpNow()
{
}

void sleepNow()
{
	byte adcsraSave = ADCSRA;
	ADCSRA &= ~ bit(ADEN);
	byte prrSave = PRR;
	PRR &= 0xFF;

	attachInterrupt(1,wakeUpNow, CHANGE );

	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();

	MCUCR = MCUCR | bit(BODSE) | bit(BODS);
	MCUCR = MCUCR & ~ bit(BODSE) | bit(BODS);

	sleep_cpu();
	sleep_disable();

	detachInterrupt(1);

	PRR = prrSave;
	ADCSRA = adcsraSave;

}

void setup() {
	#if DEBUG
		serial.begin(57600);
	#endif

	rf12_initialize(THIS_NODE, RF12_868MHZ);
	rf12_sleep(0);

	pinMode(3, INPUT);

	#if DEBUG
		serial << "Initialized..." << endl;
	#endif
}

void loop()
{
	#if DEBUG
		serial << "Going to sleep..."<< endl;
	#endif

	sleepNow();

	// waiting for display (interruption will continue from here)
	#if DEBUG
		serial << "Steped on the scale..." << endl;
	#endif

	// make sure that LCD is active
	_t = millis();
	while (lcdA<1023 && lcdB< 1023 && lcdC<1023 && (millis()-_t<10000))
	{
		lcdA = analogRead(A1);
		lcdB = analogRead(A2);
		lcdC = analogRead(A3);
	}

	// starts measuring
	#if DEBUG
		serial << "Measuring..." << endl;
	#endif
	SAn = SBn = SCn = 0;
	for (int i=0; i<8; i++)
	SA[i] = SB[i] = SC[i] = 0;
	int i=0;
	while (lcdA>0 || lcdB >0 || lcdC>0)
	{
		lcdA  = analogRead(A1);
		lcdB  = analogRead(A2);
		lcdC  = analogRead(A3);
		lcd1  = digitalRead(A4);
		lcd2  = digitalRead(A5);
		lcd3  = digitalRead(3);
		lcd4  = digitalRead(4);
		lcd5  = digitalRead(5);
		lcd6  = digitalRead(6);
		lcd7  = digitalRead(7);
		lcd8  = digitalRead(8);
		lcd9  = 0;
		lcd10 = digitalRead(9);
		lcd11 = digitalRead(A0);
		lcd12 = 0;

		// decode A, B and C signals to -1, 0, 1
		pa = 0;
		if (lcdA < 342) pa=-1; else if (lcdA > 683) pa=1;
		pb = 0;
		if (lcdB < 342) pb=-1; else if (lcdB > 683) pb=1;
		pc = 0;
		if (lcdC < 342) pc=-1; else if (lcdC > 683) pc=1;
		lcdA = pa; lcdB = pb; lcdC = pc;

		if (lcdA!=0 && lcdB==0 && lcdC==0 || lcdA==0 && lcdB!=0 && lcdC==0 || lcdA==0 && lcdB==0 && lcdC!=0)
		{
			if (lcdA==1 || lcdB==1 || lcdC==1)
			{
				lcd1 = 1-lcd1;
				lcd2 = 1-lcd2;
				lcd3 = 1-lcd3;
				lcd4 = 1-lcd4;
				lcd5 = 1-lcd5;
				lcd6 = 1-lcd6;
				lcd7 = 1-lcd7;
				lcd8 = 1-lcd8;
				lcd9 = 1-lcd9;
				lcd10 = 1-lcd10;
				lcd11 = 1-lcd11;
				lcd12 = 1-lcd12;
			}

			if (lcdA != 0)
			{
				SA[0] += lcd1;
				SA[1] += lcd2;
				SA[2] += lcd3;
				SA[3] += lcd4;
				SA[4] += lcd5;
				SA[5] += lcd6;
				SA[6] += lcd7;
				SA[7] += lcd8;
				SA[8] += lcd9;
				SA[9] += lcd10;
				SA[10] += lcd11;
				SA[11] += lcd12;
				SAn++;
			}
			if (lcdB != 0)
			{
				SB[0] += lcd1;
				SB[1] += lcd2;
				SB[2] += lcd3;
				SB[3] += lcd4;
				SB[4] += lcd5;
				SB[5] += lcd6;
				SB[6] += lcd7;
				SB[7] += lcd8;
				SB[8] += lcd9;
				SB[9] += lcd10;
				SB[10] += lcd11;
				SB[11] += lcd12;
				SBn++;
			}
			if (lcdC!=0)
			{
				SC[0] += lcd1;
				SC[1] += lcd2;
				SC[2] += lcd3;
				SC[3] += lcd4;
				SC[4] += lcd5;
				SC[5] += lcd6;
				SC[6] += lcd7;
				SC[7] += lcd8;
				SC[8] += lcd9;
				SC[9] += lcd10;
				SC[10] += lcd11;
				SC[11] += lcd12;
				SCn++;
			}

			i++;
		}

	}

	// measuring is done
	#if DEBUG
		serial << "Done..." << endl;
	#endif

	// finding the average of signals values during measuring period
	// not 100% correct, but the fastest way I could think of
	for (int i=0;i<12;i++)
	{
		A[i] = (1.0 * SA[i] / SAn >0.5);
		B[i] = (1.0 * SB[i] / SBn >0.5);
		C[i] = (1.0 * SC[i] / SCn >0.5);
	}

	// decoding
	float weight = 10.0*getDigit(6,7,8) + 1.0*getDigit(3,4,5) + 0.1*getDigit(0,1,2);

	/*
		#if DEBUG
		serial << "A ";
		for (int i=0;i		serial << " - ";
		serial << "B ";
		for (int i=0;i		serial << " - ";
		serial << "C ";
		for (int i=0;i		serial << " - ";
		#endif
	*/

	#if DEBUG
		serial << "Weight is " << weight << " kg" << endl;
	#endif
	if (weight > 5.0)
	{
		#if DEBUG
			serial << "Sending weight..." << endl;
		#endif

		rf12_sleep(-1);
		while (!rf12_canSend()) rf12_recvDone();
		rf12_sendStart(RF12_HDR_ACK | RF12_HDR_DST | DEST_NODE, &weight, sizeof(weight));
		rf12_sleep(0);

		#if DEBUG
			serial << "   ... sent!" << endl;
		#endif
	}
	else
	{
		#if DEBUG
			serial << "Sending skipped. Weight is below threshold value!" << endl;
		#endif
	}

	delay(200);
}

The last step was to collect the weight sent from the wireless enabled scale to the central Homy system. This information is persisted in database and posted to Facebook wall. This will not be described in this post, since it is similar to Facebook integration I have described in one of the previous posts.

Final look

And for the end, small video showing the whole functionality:

© 2011 – 2012, Quo Vadis ?. All rights reserved.

Loading

65 thoughts on “Hacking a weighing scale”

  1. Hi Dušan,

    I was trying to do what you did in this article, but not the weight scale, is a pH meter (like this one: https://www.allaboutcircuits.com/news/teardown-tuesday-digital-ph-meter/).

    But the problem is, when I connect the wire to the arduino, my pH meter will going crazy, the value is pretty unstable. Looks like some noise effect it, I tried to put the resistor and diode between pH meter and arduino, but it’s not working.

    I was wondering, if you could give me some advise? Thanks a lot.

    1. Hi Alex,

      That is one nice idea that you have there.

      My best guess would be to use common ground; keep in mind electronics is not my stronger side.

      Good luck

  2. Hey,

    I adapted this for a Soehnle (German product) scale. Had a few things to solve with slightly different encoding but it works like a charm now and transmits my weight + timestamp to a cpp-listener running on my RpI 2 via 2.4 GHz.

    Thanks a all thumbs up!

  3. hi, great project!!!

    I’ve had this idea for a automatic pet feeder for my rabbits but had no idea how to do it

    is it possible you can scrub all the wireless+streaming+extras out of your sketch so i can try to learn the basic lcd decoding part?

    my arduino coding is still very rudimentary and trying to take on your sketch is indeed a mammoth task… it’s quite difficult for a beginner like me to try to adapt your awesome breakthrough to my needs (without some training wheels… like a few comments to explain)

    i already worked out my lcd pinout by using scotch tape to block connections between the elastomeric connector and pcb (leaving only 2 connections at a time in every possible combination and seeing what still lit up on screen)

    1. Hello Kennie,

      The wireless and streaming part is really minimal. Remove all rf12* commands and include of JeeLib.h. If you want to remove Streaming library, you would need to change every Serial command from serial < < to Serial.print.

      The rest of the code is not that arduino specific, just basic C++ stuff.

      I wish you success with you project. Looks like you are on good path. Just keep on and share the results.

      1. thanx for the quick reply… it’s just my eyes just glaze over when i try to get a grasp on ur code..

        i ran into some problems when i just wrote a small simple sketch to do few digital/analog reads on a loop just to see what kind of raw data i could get from the screen

        when i hook up the screen to my arduino mega my values seem to flutuate wildly without a discernable pattern or reason even when the screen’s readout was a constant value (does the both systems need to have the same power source so they share a common ground?)…also, the contrast on the screen got very low and the digits were almost unreadble(did u experience this at all?)

        My screen is A to D and 1 to 9 and just that one small detail means i have to do some reworking of ur code (and with my limited coding knowledge nothing is “basic”…. not even BASIC is basic to me)

        But as it can’t be said enough… thanx for ur work…such a intelligent novel way to “internet of things” every everyday items

        i’ll try my best to power through

  4. Hi,
    i have Digital orque adaptor.i just opened it i found their is Black-dot,their is LCD display which is having 16 pins.
    now i want to transfer this LCd displayed data to 8051 microcontroller.
    i want to know how can i do that?
    i dont have detailed description of LCD which is mounted on that.
    i am thinking to use cables and decode each signal from LCD pins and process it to microcontroller.
    but i dont have oscilloscope inorder to read at each pins of LCD .
    i dont know which pins of lCd signifies what..?
    please help me out.
    Can anyone help me out any alternate way by which i can decode the data from 16 pins of lCD and send to microcontroller?

    1. Hello,

      As explained in previous reply, I also didn’t have any LCD pinout nor datasheet. Just use your own logic and google 🙂

  5. Hi,
    I am also working same kind of project. i want to know how did u decode each signal from LCD of weighing scale.
    can u tell me how did u decode each signal from LCD pins?
    and how did u come to conclusion that respective pins are generating A,B and C.

    1. Hello Rahul,

      I have connected the pins to Arduino analog inputs and printed the sampled values to console. After that, I just imported all of that into excel, made some graphs. Similar result would be if you used oscilloscope, which I didn’t have at that point.

      Then it is just a little bit of logic, and trial and error in order to understand how really coding works.

  6. Thank you for instructions. I made my own wifi scale with your help. I have a Sencor scale with same LCD. I used arduino pro mini too, but my code send the data over a secondary serial port to an ESP8266 board. The ESP connect directly to a router, and when connected, store weight to my MySql server with a PHP script. The LCD readings not correct every time, but 99% it reads good values.

  7. Did you know the Jeenode board ?
    It is an arduino compatible board with RFM12B integrated.

    1. Sure… The central node of my home automation network is JeeNode, also some other attached devices (presence notification, irrigation control unit, …)

  8. Hi. I`m trying to follow this project but im having trouble getting a stable analogRead.
    -my LCD has 4 backplanes. im receiving around 0,215,430,645.
    -i already mapped the LCD by turning the segments on and off with digitalWrite.

    How can I translate this analogReads? whats ON and OFF? how can i get it stable?

    1. Hello Bruno,

      As you could see in my code, I got 3 levels of signal (0-342, 342-683, 683-1000) that were coded as -1, 0, 1, and then depending on backplane signal (1, -1) encoded into 0 or 1.

      This might be totally different in your case.

      I would suggest you experiment with different polarity of backplane signal and different segment voltage levels to figure out coding in your case; I guess this is different with every LCD. Also, datasheet for LCD can help.

      Cheers.

    1. Unfortunately, I cannot see it without fully disassembling the scale.

  9. Hi Dušan,

    I am thinking on getting my hands on this project too .-).

    Can you please clarify if the Arduino pinout that you posted is complete?
    I think that there is no reference to pin number 9 on where it should be connected.

    Another question I have is that what kind of batteries does your weighting scale use?
    I ask because you refer two additional wires for 5v supply (for arduino and rfm12b) but in my case, my scale (also Grundtal) only uses two 1,5v AA batteries.

    Maybe I will need to change those two 1,5v batteries to a 9v battery and then add an LM7805 to limit the voltage…

    Your insights would be very helpful.
    Thanks

    1. Hey Miguel,

      The pinout is correct. You can see also in code that pins 9 and 12 are not read. This I did on purpose, in order to save some pins since I had only 10 pins free on Arduino. You will be fine without this pin only in case you don’t have 9x kg (digits 3 and 9 will give the same readout), otherwise you would need to include it.

      My scale has 9V battery, so I didn’t have any problems with power source. Voltage regulator in your case would be an option.

  10. Hi Dušan,

    First of all, let me thank you for posting such great projects/hacks.
    Can I ask you what kind of device did you use to turn on/off those ceiling lamps? Did you dismantled the wall sockets you’ve shown in the pictures?

    Do you consider to allow access to the code of your applications?
    Once more, thanks for your projects.
    Best

    1. Hey Miguel,

      I guess you meant to send comment to another post. There I already answered.

      Cheers.

    1. Hi Rishi,

      The whole pinout diagram is in the picture “Arduino pinout” in the post. It is really simple.

  11. Hi Dušan,

    Finally I got it working! 😀
    I found that I had a hardware problem which caused the 7th bit to go high every time. I have posted the working sketch here: http://troels.leegaard.org/misc/grundtal20047/sketch.pde

    The sketch is for the Duemilanove as I’m still awaiting for a Mini Pro to arrive.
    Feel free to delete my previous posts as they’ll probably just confuse other visitors!

    1. Hey Troels,

      Good to hear that! Feel free to share any details about the final design…

    2. Hi Troels,

      Good work.
      What’s the pin diagram?
      Is it necessary some ci or resistor in some pin?
      The sketch work in Arduino UNO?

      tks

  12. Hi Dusan,

    I am now a bit closer to having it working. Right now I’m getting this output:


    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000000000 - B 000011110 - C 000011110 - D 000011100
    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000000000 - B 000000000 - C 000000000 - D 000000000
    Measuring...
    Done...
    A 000011111 - B 000000000 - C 000000000 - D 000000000

    It seems like the timing for when to start/stop counting is messed up, as the output should have been:
    A 000011111 – B 000011110 – C 000011110 – D 000011100

    Code can be found here: http://troels.leegaard.org/misc/scale.ino

    Do you think you can help me out on this?

    1. I’m getting closer:


      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 001111100 - B 000000000 - C 000000000 - D 000000000
      A 001111100 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000001010 - C 000000000 - D 000000000
      A 000000000 - B 000001010 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000000000 - B 000001010 - C 000011110 - D 000000000
      A 000011111 - B 000001010 - C 000011110 - D 000000000
      A 000011111 - B 000001010 - C 000011110 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000011100
      A 000000000 - B 000000000 - C 000011110 - D 000011100
      A 000001010 - B 000001010 - C 000011110 - D 000011100
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000000000 - D 000000000
      A 000000000 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000
      A 000001010 - B 000000000 - C 000011110 - D 000000000

      Still aiming for the same result:
      A 000011111 – B 000011110 – C 000011110 – D 000011100

      But why is the result getting splitted?
      http://troels.leegaard.org/misc/closer.ino

      1. Hi Dusan,

        Sorry for all the posts.. just made a little progress.. getting a lot more lines of output now, but the last outputted lines seems to be right every time now:


        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100
        A 000011110 - B 000001010 - C 000011110 - D 000011100

        1. Hey…

          This already looks much better… Did you get any stable value afterall?

          1. Hi Dusan,

            I’m now getting stable, but wrong, output (66.2kg):
            A 001111111 - B 001010010 - C 001111000 - D 001011000
            But unfortunately this should be:
            A 001111111 - B 001010110 - C 001111010 - D 001011000

            And this one (0.0kg):
            A 000011111 - B 000001110 - C 000011110 - D 000011000
            But this should be:
            A 000011111 - B 000001010 - C 000011110 - D 000011100

            I can’t figure out why this happens.. Code can be seen here: http://troels.leegaard.org/misc/better.ino

            Maybe if the averaged bits were calculated for only the last 10 or 100 values in array instead of the full array it would be more precise, but I cant figure out how to do that..

            Thanks for your time and interest! 🙂

  13. Hi again,

    I got the Grundtal 20047 myself. As far as I can see Vince got mixed up the pin numbering. (Unless IKEA changed the display without changing the serial number)

    The pin arrangement I found is to be seen here: http://troels.leegaard.org/misc/grundtal20047.pdf

    I have made a small sketch (http://troels.leegaard.org/misc/unit.pde) which verifies the pin arrangement by checking backplane A and lcdpin 9 when outputting KG/LB/ST (can be changed on the back of the scale). In this case the backplanes are connected to analog inputs on the Arduino and lcdpin9 to a digital input. The backplane is low and the lcdpin high when the KG symbol is lid.

    I have been scratching my head getting further on, merging with your previous code – so any help will be much appreciated! 🙂

      1. From what I can remmember:
        – input from plane pins was 0, ~500, ~1000; which was encoded into -1, 0 and 1 in my case (pa, pb, pc).
        – at one point in time, only one plane can be active (1 or -1); the other 2 are inactive (0)
        – when pa, pb, pc is 1, then p1, p2, …, p12 need to be inverted
        – when pa, pb, pc is -1, then p1, p2, …, p12 are ok

  14. Hi Dusan,

    Did you and Vince ever solve the hacking of the 20047 model?

    I think I got the first part covered, but I have problems decoding the output..

    1. Hello,

      I didn’t manage to follow Vince any further in his investigation. Maybe he can give some input here, in case he follows this discussion by any chance.

  15. Hey, I’m are doing a similar kind of project.
    I have been trying to understand your code, but have some problems with it..
    If you’re stil active here I’d have some questions 🙂

    Thanks
    Gard

    1. Hi Gard,

      What is your project about? Feel free to drop any question.

      One part of the code (one handling decoding of LCD) is specific. Depending on LCD display this part needs to be changed (like in Vince’s case).

      1. We are firstly trying to hook up a scale to an arduino. After that we’ll probably try to send the data online somewhere. We figured out the segments, here’s a link to the image: http://img13.imageshack.us/img13/5059/segmenttiwlevy.png
        I figured out the decoding part of the code, and I think your code would work for our display. We are still getting 0 weight, but we’ll keep debugging the code.
        We did make the program to print the values of ABC and first four segments, and we saw the backplanes go on and the required segments at the same time.

        Im not fully understand the part of the code with the if’s after decoding the 1,0,-1.
        the part with the SA[n],SB[n],SC[n].

        Thanks for your interest 🙂

        1. The part with SA, SB, SC is all about trying to find the most common/frequent state of the segments from the moment LCD is turned on. Finding arithmetic median value gives correct weight in 99% of the cases.
          This is all because weight on LCD goes from 0 to target weight, and there is some flickering as well.

          Maybe this part could have been done in a much easier way, this was the first thing that came to my mind at that point 🙂

  16. Hi Dusan,

    dis you get an idea since I have put the last results ? Maybe you didn’t have time…I understand.

    Vince

  17. Hi Dusan,

    I went a little further in the code but now I’m stuck. I observed that the backplanes could take four different ranges, so four different states. So for lcdA, B, C, D, I do : if (lcdX == 0) px=-1; else if (lcdX >= 150 && lcdX = 350 && lcdX = 500) px=2;

    Now, for each measure of the same weight, I still have the following result (That’s a good news!): A 000111000 – B 001110100 – C 000000000 – D 000000000

    Now I have to understand how I can decode it, according to the lcd display map I drew http://www.arpege-studio.com/Grundtal/ and the Jata_Hogar_490 scale project.

    I already feel the headache arrived! If with these new elements, you have an idea to propose me.

    Thanks.
    Vince

    1. Hi Vince,

      lcdX can take value 0 to 1024. Your if statement looks really strange.

      What is the weight you put on scale? What do you get in the console if you print out values for lcdA – lcdD, lcd1 – lcd9 in while loop?

        1. Try this:

          1) Swap A< ->C and B< ->D like this:

          lcdA = analogRead(A3);
          lcdB = analogRead(A4);
          lcdC = analogRead(A1);
          lcdD = analogRead(A2);

          2) Change decoding of A, B, C & D like :

          pa = 0;
          if (lcdA < 100) pa=1; pb = 0; if (lcdB < 100) pb=1; pc = 0; if (lcdC > 500) pc=1;
          pd = 0;
          if (lcdD > 500) pd=1;

          3) Extend the condition like this:

          if ((lcdA!=0 && lcdB==0 && lcdC==0 && lcdD==0 ||
          lcdA==0 && lcdB!=0 && lcdC==0 && lcdD==0 ||
          lcdA==0 && lcdB==0 && lcdC!=0 && lcdD==0 ||
          lcdA==0 && lcdB==0 && lcdC==0 && lcdD!=0) &&
          (lcd1!=0 || lcd2!=0 || lcd3!=0 || lcd4!=0 || lcd5!=0 || lcd6!=0 || lcd7!=0 || lcd8!=0 || lcd9!=0))

          4) lcd2 seems not to be conected, check the wire!

  18. Hi,
    In our case we have a 13 pin LCD, instead of the 15 pin shown above in your experiment. In this case, do we assign 3 pins for A,B,C, 1 for ground and the remaining 9 for the lcd displays? In this case it would mean we have three hex digits right? or is it possible to drive 4 lcd digits too?

    Thanks,
    Krishna

    1. Hi Krishna,

      Are you using same scale (Grundtal)?

      In any case the LCD must be driven in a different way. No way I can tell what is the correct way to control the LCD in that case. I am afraid you need to figure it out by “playing” with LCD (as I did as well).

      Feel free to share your success once you have it figured out.

    2. Hi Krishna,

      First of all, thanks for your tutorial Dusan !

      In fact I have the same problem that you. My scale is the Grundtal from IKEA but unfortunately I have only 13 pins on it.

      When the scale is On, I measure 1.44V between each lcd pins and GND. Don’t know if it’s usefull to know that.

      I have wired it like this: lcdA=>A1 / lcdB=>A2 / lcdC=>A3 / lcd1=>A4 / lcd2=>A5 / lcd3=>3 / lcd4=>4 / lcd5=>5 / lcd6=>6 / lcd7=>7 / lcd8=>8 / lcd9=>9 / lcd10=>A0

      Here is what I have in debug mode on the serial:
      A B C Weight is 0.00 kg
      Sending skipped. Weight is below threshold value!
      Going to sleep…
      Steped on the scale…
      Measuring…
      Done…

      Thanks for your help
      Vince

      1. Hi Vince,

        From what you have described, it looks like either wiring or code is not working with your version of LCD.

        It is hard to say how that 13 pin display works. Try to find its serial number and some datasheet for it. Otherwise you would need to figure it out yourself.

        I found really good info on LCD decoding in http://code.google.com/p/casainho-projects/wiki/SdCardBathroomScale . Signals lcdA, lcdB and lcdC are backplane signals, and these guys are sync signals for the rest of the signals (lcd1-lcd?). You can not just measure DC voltage between 2 pins, you will not get usable value, and anyway the relevant voltage should be between backplane pin (lcdA, lcdB or lcdC) and segment pin (lcd1-lcd?).

        I suggest you guys use different approach, use 3V DC and apply it to lcdA (or lcdB, or lcdC) and other pins (lcd1-lcd?). In that way you would be able to figure out which pins are backplane and which are the segment pins. This is how I figured out what is each pin for.

        Good luck!

        1. Hi Dusan,

          thanks for your explanations and the casainho-projects documentations. I followed your advice and found which pins are backplane and which are the segments pins. Here is the result: http://www.arpege-studio.com/Grundtal/

          Despite the code samples available, I fail to fit my case. I hope you can help me and that software’s part is a breeze for you!

          Regards.
          Vince

          1. Hi Vince,

            This could be the code that works for your display:

            #include <JeeLib.h>
            #include <SoftwareSerial.h>
            #include <Streaming.h>
            #include <avr/sleep.h>
             
            #define DEBUG 0
            #define THIS_NODE 15
            #define DEST_NODE 13
             
            #if DEBUG
                SoftwareSerial serial(0, 1);
            #endif
             
            int lcdA=0,lcdB=0,lcdC=0,lcdD=0;
             
            int pa,pb,pc,pd;
            bool lcd1,lcd2,lcd3,lcd4,lcd5,lcd6,lcd7,lcd8,lcd9;
             
            unsigned int SAn, SBn, SCn, SDn;
            unsigned int SA[9], SB[9], SC[9], SD[9];
            bool A[9], B[9], C[9], D[9];
             
            unsigned int _t;
             
            int getDigit(int d)
            {
            	// d=0,1,2,3
            	// 
            	int i = 2*d+1;
            	int j = 2*d+2;
            	
                if ( A[i] &&  A[j] &&  B[i] && !B[j] &&  C[i] &&  C[j] &&  D[j]) return 0;
                if (!A[i] && !A[j] &&  B[i] && !B[j] &&  C[i] && !C[j] && !D[j]) return 1;
                if ( A[i] && !A[j] &&  B[i] &&  B[j] && !C[i] &&  C[j] &&  D[j]) return 2;
                if ( A[i] && !A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] &&  D[j]) return 3;
                if (!A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] && !D[j]) return 4;
                if ( A[i] &&  A[j] && !B[i] &&  B[j] &&  C[i] && !C[j] &&  D[j]) return 5;
                if ( A[i] &&  A[j] && !B[i] &&  B[j] &&  C[i] &&  C[j] &&  D[j]) return 6;
                if ( A[i] && !A[j] &&  B[i] && !B[j] &&  C[i] && !C[j] && !D[j]) return 7;
                if ( A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] &&  C[j] &&  D[j]) return 8;
                if ( A[i] &&  A[j] &&  B[i] &&  B[j] &&  C[i] && !C[j] &&  D[j]) return 9;
                return 0;
            }
             
            void wakeUpNow()
            {
            }
             
            void sleepNow()
            {
                byte adcsraSave = ADCSRA;
                ADCSRA &= ~ bit(ADEN);
                byte prrSave = PRR;
                PRR &= 0xFF;
             
                attachInterrupt(1,wakeUpNow, CHANGE );
             
                set_sleep_mode(SLEEP_MODE_PWR_DOWN);
                sleep_enable();
             
                MCUCR = MCUCR | bit(BODSE) | bit(BODS);
                MCUCR = MCUCR & ~ bit(BODSE) | bit(BODS);
             
                sleep_cpu();
                sleep_disable();
             
                detachInterrupt(1);
             
                PRR = prrSave;
                ADCSRA = adcsraSave;
             
            }
             
            void setup() {
                #if DEBUG
                    serial.begin(57600);
                #endif
             
                rf12_initialize(THIS_NODE, RF12_868MHZ);
                rf12_sleep(0);
             
                pinMode(3, INPUT);
             
                #if DEBUG
                    serial << "Initialized..." << endl;
                #endif
            }
             
            void loop()
            {
                #if DEBUG
                    serial << "Going to sleep..."<< endl;
                #endif
             
                sleepNow();
             
                // waiting for display (interruption will continue from here)
                #if DEBUG
                    serial << "Steped on the scale..." << endl;
                #endif
             
                // make sure that LCD is active
                _t = millis();
                while (lcdA<1023 && lcdB< 1023 && lcdC<1023 && lcdD<1023 &&(millis()-_t<10000))
                {
                    lcdA = analogRead(A1);
                    lcdB = analogRead(A2);
                    lcdC = analogRead(A3);
            		lcdD = analogRead(A4);
                }
             
                // starts measuring
                #if DEBUG
                    serial << "Measuring..." << endl;
                #endif
                SAn = SBn = SCn = SDn = 0;
                for (int i=0; i<9; i++)
            		SA[i] = SB[i] = SC[i] = SD[i] = 0;
                int i=0;
                while (lcdA>0 || lcdB >0 || lcdC>0 || lcdD>0)
                {
                    lcdA  = analogRead(A1);
                    lcdB  = analogRead(A2);
                    lcdC  = analogRead(A3);
            		lcdD  = analogRead(A4);
            		
                    lcd1  = digitalRead(A5);
                    lcd2  = digitalRead(A6);
                    lcd3  = digitalRead(3);
                    lcd4  = digitalRead(4);
                    lcd5  = digitalRead(5);
                    lcd6  = digitalRead(6);
                    lcd7  = digitalRead(7);
                    lcd8  = digitalRead(8);
                    lcd9  = digitalRead(9);
             
                    // decode A, B, C and D signals to -1, 0, 1
                    pa = 0;
                    if (lcdA < 342) pa=-1; else if (lcdA > 683) pa=1;
                    pb = 0;
                    if (lcdB < 342) pb=-1; else if (lcdB > 683) pb=1;
                    pc = 0;
                    if (lcdC < 342) pc=-1; else if (lcdC > 683) pc=1;
                    pd = 0;
                    if (lcdD < 342) pd=-1; else if (lcdD > 683) pd=1;
            		lcdA = pa; lcdB = pb; lcdC = pc; lcdD = pd;
             
                    if (lcdA!=0 && lcdB==0 && lcdC==0 && lcdD==0 || 
            			lcdA==0 && lcdB!=0 && lcdC==0 && lcdD==0 || 
            			lcdA==0 && lcdB==0 && lcdC!=0 && lcdD==0 || 
            			lcdA==0 && lcdB==0 && lcdC==0 && lcdD!=0)
                    {
                        if (lcdA==1 || lcdB==1 || lcdC==1 || lcdD==1)
                        {
                            lcd1 = 1-lcd1;
                            lcd2 = 1-lcd2;
                            lcd3 = 1-lcd3;
                            lcd4 = 1-lcd4;
                            lcd5 = 1-lcd5;
                            lcd6 = 1-lcd6;
                            lcd7 = 1-lcd7;
                            lcd8 = 1-lcd8;
                            lcd9 = 1-lcd9;
                        }
             
                        if (lcdA != 0)
                        {
                            SA[0] += lcd1;
                            SA[1] += lcd2;
                            SA[2] += lcd3;
                            SA[3] += lcd4;
                            SA[4] += lcd5;
                            SA[5] += lcd6;
                            SA[6] += lcd7;
                            SA[7] += lcd8;
                            SA[8] += lcd9;
                            SAn++;
                        }
                        if (lcdB != 0)
                        {
                            SB[0] += lcd1;
                            SB[1] += lcd2;
                            SB[2] += lcd3;
                            SB[3] += lcd4;
                            SB[4] += lcd5;
                            SB[5] += lcd6;
                            SB[6] += lcd7;
                            SB[7] += lcd8;
                            SB[8] += lcd9;
                            SBn++;
                        }
                        if (lcdC!=0)
                        {
                            SC[0] += lcd1;
                            SC[1] += lcd2;
                            SC[2] += lcd3;
                            SC[3] += lcd4;
                            SC[4] += lcd5;
                            SC[5] += lcd6;
                            SC[6] += lcd7;
                            SC[7] += lcd8;
                            SC[8] += lcd9;
                            SCn++;
                        }
                        if (lcdD!=0)
                        {
                            SD[0] += lcd1;
                            SD[1] += lcd2;
                            SD[2] += lcd3;
                            SD[3] += lcd4;
                            SD[4] += lcd5;
                            SD[5] += lcd6;
                            SD[6] += lcd7;
                            SD[7] += lcd8;
                            SD[8] += lcd9;
                            SDn++;
                        }			
             
                        i++;
                    }
             
                }
             
                // measuring is done
                #if DEBUG
                    serial << "Done..." << endl;
                #endif
             
                // finding the average of signals values during measuring period
                // not 100% correct, but the fastest way I could think of
                for (int i=0;i<9;i++)
                {
                    A[i] = (1.0 * SA[i] / SAn >0.5);
                    B[i] = (1.0 * SB[i] / SBn >0.5);
                    C[i] = (1.0 * SC[i] / SCn >0.5);
            		D[i] = (1.0 * SD[i] / SDn >0.5);
                }
             
             
            	#if DEBUG
            	serial << "A ";
            	for (int i=0;i<9;i++) serial << (A[i]?"1":"0");
            	serial << " - ";
            	serial << "B ";
            	for (int i=0;i<9;i++) serial << (B[i]?"1":"0");
            	serial << " - ";
            	serial << "C ";
            	for (int i=0;i<9;i++) serial << (C[i]?"1":"0");
            	serial << " - ";
            	serial << "D ";
            	for (int i=0;i<9;i++) serial << (D[i]?"1":"0");
            	serial << " - ";
            	#endif
              
                // decoding
                float weight = 100.0*getDigit(3) + 10.0*getDigit(2) + 1.0*getDigit(1) + 0.1*getDigit(0);
              
                #if DEBUG
                    serial << "Weight is " << weight << " kg" << endl;
                #endif
                if (weight > 5.0)
                {
                    #if DEBUG
                        serial << "Sending weight..." << endl;
                    #endif
             
                    rf12_sleep(-1);
                    while (!rf12_canSend()) rf12_recvDone();
                    rf12_sendStart(RF12_HDR_ACK | RF12_HDR_DST | DEST_NODE, &weight, sizeof(weight));
                    rf12_sleep(0);
             
                    #if DEBUG
                        serial << "   ... sent!" << endl;
                    #endif
                }
                else
                {
                    #if DEBUG
                        serial << "Sending skipped. Weight is below threshold value!" << endl;
                    #endif
                }
             
                delay(200);
            }
            

            Basically, additional variables for backplane signal D are added and getDigit function is adopted. In case of bad values, investigate about encoding/decoding 7 segment display; this could help about getDigit function.

            Hope this helped.

          2. Hi Dusan,

            really appreciate your help! Unfortunately, it’s still doesn’t work. I’ve tried with d=0, d=1, d=2, d=3 and I always get the same result:
            A 000000000 – B 000000000 – C 000000000 – D 000000000 – Weight is 0.00 kg

            I have found another link that explain how to hack a weighing scale and this Jata Hogar scale got the same LCD (I’ve checked the 13 pins with my scope) than the new one they put in the Grundtal N° 20047. But the project isn’t written for the Arduino…too bad for me !
            http://code.google.com/p/casainho-projects/wiki/SdCardBathroomScale#Technical_details_–_Scale_Jata_Hogar_490

            If you don’t have time to explore this for me, could you just tell me what is the serial number of your Grundtal scale please ? I think it could be 20325: http://img.2ememain.be/f/normal/97732486_1-ikea-grundtal-personenweegschaal.jpg

            Thanks again.
            Vince

          3. Hi,

            From what I can remmember, waveforms were more like for Scale Fagor BB-90. Algorithm in my code handles decoding that kind of waveforms. I suggest you deep little in the code and compare it with the one for your display. Let me know how it went.

            Scale serial is 20325, it lookes exactly like in that picture.

  19. Hi,

    great job, I am working on something similar, just using SI labs RF Dev kit.
    I tried your bathroom scale code for Arduino, but it doesn’t compile, I think it got somehow mangled when converted for web. Would you care to post the original source code somewhere?

    thanks.

    1. Hi Radek,

      Just now I see that code is mangled. I have updated the code, please try now; it should compile. Make sure you get latest libraries from http://jeelabs.net/projects/cafe/repository.

      I wish you success in your project. Let us know the results; your approach seems interesting.

  20. Ah should’ve looked around a little more closely on your blog before asking. This Homy thing is AWESOME! Great work, and thank you so much for sharing!!

  21. Quick question on this. What were you communicating with wirelessly outside of the scale? I assume the radio described can’t connect to a wifi network, so did you just build another arduino module with another RFM12B transmitter on it and hook that up to your computer for the Facebook posting part?

    Really cool project! I started researching this exact thing yesterday and I’m excited to build my own!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.