Squiz3rs hemautomation med egen androidapp och Raspberry Pi

Berätta om dina pågående projekt.
Användarvisningsbild
squiz3r
Inlägg: 5424
Blev medlem: 5 september 2006, 20:06:22
Ort: Lund
Kontakt:

Squiz3rs hemautomation med egen androidapp och Raspberry Pi

Inlägg av squiz3r »

Syfte:
Lampor i lägenheten skall tändas och släckas när jag kommer in i rummet eller lämnar rummet. Det skall gå att ställa in en veckarklocka från mobilappen, när larmet går så skall taklampor och sänglampa tändas och radion skall startas. Lampor skall även kunna styras manuellt från app eller internetsida. Temperatur och övriga loggade mätdata skall kunna ses i grafer på internetsida eller i app.

För att göra projektet lite roligare och trigga mig till att spara på el så är min idé att göra en livssimulator i telefonen. En autonom "gubbe" bor i en omgivning. Om elförbrukningen är hög blir det dåligt klimat, översvämningar ont om mat osv. Inte bra för gubben som blir ledsen alltså. Istället för att bara vänta på att klimatet skall bli bättre när elförbrukningen går ner kan man snabba på det och "köpa" t.ex. en matbit till gubben mot att alla lampor i lägenheten slocknar i en timme.

Tillvägagångssätt:
Allt kommer att styras centralt från en Raspberry Pi, en liten dator stor som ett kreditkort. Denna kommer att ha servermjukvara (mySQL och Apache2) installerat och vara tillgänglig från internet (forwardad port och dynDNS via noip.com).
Bild

Till denna skall ett 1-wire nätverk kopplas med:
- inne temp
- ute temp
- temp i fiskdamm (ytvatten)
- temp i fiskdamm (bottenvatten)
- lufttryck
- hygrometer ute
- hygrometer inne

NEXA-brytare eller Julas ANSLUT-brytare kommer kunna styras från servern via 433 Mhz radio. Rörelsedäckare (PIR-sensorer) samt dörrbrytare kommer kommunicera med servern trådlöst på samma våglängd.
Bild

Var jag står nu:
Jag har i några dagar haft en tråd i allmänt kategorin om detta ämnet men jag tycker att det är dags för en projekttråd nu. För att få den ordentligt uppstrukturerad och lättläst valde jag att göra en ny tråd här i projektdelen. Hoppas det är ok!

Jag har kopplat in en temperaturgivare, DS1820, enligt detta enkla (lånade) schema.
Bild

Nu har jag ett pythonscript, körs på Raspbarryn så fort den startar, som tar en temperaturmätning var tionde sekund och kallar på en php-fil som sparar mätvärdet i en MySQL databas. Sen har jag en php-fil som presenterar det i en graf med hjälp google charts.

Python skriptet:

Kod: Markera allt

import urllib2
import os
import time

# Adresses for the write-to-database php file
URL = "http://localhost/addSensorReadings.php"
GET1 = "?zone="
GET2 = "&value="

## ENABLE GPIO IN THE /etc/rc.local SCRIPT
## ALSO ADD /home/pi/readSensors.py SO THIS SCRIPT STARTS 
## EVERY TIME RPI STARTS

# Adress to the therometers
BASE_DIR = '/sys/bus/w1/devices/'
###ALL_DIR = BASE_DIR + "w1_bus_master1/w1_master_slaves/"
###DEVICE_ALL = glob.glob(ALL_DIR)
###DEVICE_ID_LIVINGROOM = DEVICE_ALL[0]
DEVICE_ID_LIVINGROOM = '10-0008014c61ed'
TOP_DIR = '/w1_slave'
DEVICE_LIVINGROOM = BASE_DIR + DEVICE_ID_LIVINGROOM + TOP_DIR


# Read lines from file
def readTempRaw():
    f = open(DEVICE_LIVINGROOM, 'r')
    lines = f.readlines()
    f.close()
    return lines


# Extract temperature from lines
def readTemp():
    lines = readTempRaw()
    while lines[0].strip()[-3:] != 'YES': # Ensure temp sensor is read correct
        time.sleep(0.2)
        lies = readTempRaw()
    indexOfEq = lines[1].find('t=')
    if indexOfEq != -1:
        temp = float(lines[1][indexOfEq + 2 :])/1000.00
        return temp


# Main loop
while True:
    # Read temp
    tempLivingroom = readTemp();
    #Print it on screan
    #print(tempLivingroom)
    # Insert it into MYSQL database
    response = urllib2.urlopen(URL + GET1 + "Livingroom" + GET2 + str(tempLivingroom))
    s = response.read()
    # Check if insertion was sucessfull
    #if s == b'Sucess':
        #print("Sucess!")
    #else:
        #print("Failed to insert into database")
    # Sleep for 10 seconds
    time.sleep(10)
PHP-koden för att spara ner till databasen:

Kod: Markera allt

<?php
$TABLE_NAME = "readings";
$con = mysqli_connect('localhost', '***', '***', 'sensors');

if (mysqli_connect_errno()) {
    echo "Failed to connect to mysql: " .  mysqli_connect_errno();
}

$zone = $_GET["zone"];
$value = $_GET["value"];

if ($zone == "") {
    echo "Error: Zone is not set";
}else if ($value == "") {
    echo "Error: Value is not set";
}else {
   $query = "INSERT INTO " . $TABLE_NAME . " (zone, value) VALUES ('$zone', '$value')";
    $ok = mysqli_query($con, $query);
   echo $ok==1?"Sucess":"Failed";
}
mysqli_close($con);

?>
Och PHP-koden som presenterar temperaturen i en graf: (Dock kan denna bara visa en temperaturgivare i grafen än så länge)

Kod: Markera allt

<?php
$patterns = array ('/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/',
                   '/^\s*{(\w+)}\s*=/');
$replace = array ('\3/\4/\1\2', '$\1 =');
if (isset($_GET['from']))
    $from = preg_replace($patterns, $replace, $_GET['from']);
else
    $from = "";
if (isset($_GET['to']))
    $to = preg_replace($patterns, $replace, $_GET['to']);
else
    $to = "";

// String for html output
$str1 = "";

// Connect to server
$con = mysqli_connect('localhost', '***', '***', 'sensors');

if (mysqli_connect_errno()) {
    $str1 = "Failed to connect to mysql: " .  mysqli_connect_errno();
}

// Look up which sensors are saved
$query = "SELECT DISTINCT(zone) AS zone FROM readings ORDER BY zone";
$result = mysqli_query($con, $query);
$sensors = array();
while ($row = mysqli_fetch_array($result))
    $sensors[] = $row['zone'];

$str1 .= ("<table style='border:0px;'><tr><td><table style='width: 300px; padding:10px; border:1px solid #3D3D3D;'><tr><td><b>Found " . mysqli_num_rows($result) . " sensor(s)</b></td></tr>");
foreach ($sensors as $sensor) {
    $str1 .= "<tr><td>&nbsp;&nbsp;&nbsp;- " . $sensor . "</td></tr>";
}
$str1 .=("</table>");

// Table to store everything for graph..
if ($from == "")
    $queryFrom = " datetime >= '" . date('Y-m-d H:m:s', strtotime('-1 hour')) . "'";
else
    $queryFrom = " datetime >= '" . date('Y-m-d H:m:s', strtotime($from)) . "'";
if ($to == "")
    $queryTo = "";
else
    $queryTo = " AND datetime <= '" . date('Y-m-d H:m:s', strtotime($to)) . "'";
$query = "SELECT * FROM readings WHERE" . $queryFrom . $queryTo . " ORDER BY datetime DESC";
$result = mysqli_query($con, $query);
$num_plotted_times = mysqli_num_rows($result);
$last_read_temp = 999;
$table = array();
$i = 0;
while($row = mysqli_fetch_array($result)){
    // Data table
    //$table[$i] = array();
    $table[$i][0] = (string)$row['datetime'];
    $table[$i][1] = (double)$row['value'];
    $i ++;
    if ($i == 1)
        $last_read_temp = $row['value'];
}
$table = array_reverse($table);

// Find min temperature in intervall
$query = "SELECT MIN(value) AS min FROM readings WHERE" . $queryFrom . $queryTo;
$result = mysqli_query($con, $query);
$row = mysqli_fetch_array($result);
$min_temp = $row['min'];
// Find max temperature in intervall
$query = "SELECT MAX(value) AS max FROM readings WHERE" . $queryFrom . $queryTo;
$result = mysqli_query($con, $query);
$row = mysqli_fetch_array($result);
$max_temp = $row['max'];
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title>Home Tempereture</title>
    
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
    
    var handle=setTimeout(function(){window.location.reload(1);}, 10000);
     
    // Load the Visualization API and the piechart package.
    google.load('visualization', '1', {'packages':['corechart']});
     
    // Set a callback to run when the Google Visualization API is loaded.
    google.setOnLoadCallback(drawChart);
     
    function drawChart() {
    // Create our data table out of JSON data loaded from server.
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'datetime');
        data.addColumn('number', '<?php echo $sensor; ?>');
    data.addRows(<?php echo json_encode($table); ?>);
       var options = {
        'height':500
       };
    // Instantiate and draw our chart, passing in some options.
    // Do not forget to check your div ID
    var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
    chart.draw(data, options);
    }
    </script>
 </head>
 <body>  
 <center>
 <input type="checkbox" name="refresh" value="refresh" onclick="if(this.checked){handle=setTimeout(function(){window.location.reload(1);}, 10000)}else{clearTimeout(handle)}" checked> Dynamic page refresh
 <form name="input" action="index.php" method="get">
Show measurements from: <input type="text" name="from"> 
to: <input type="text" name="to"> <input type="submit" value="Submit">
</form></center>
 <div id="chart_div" style="width:100%"></div>
<?php
// How many sensors where found?
echo "<center>" . $str1 . "</td><td>";
echo "<table style='padding:10px; border:0px;'><tr><td>";
echo "Last read temperature: <b>" . number_format($last_read_temp,1) . "&deg;C</b>"; 
echo "</br>Min temperature in interval: <b>" . number_format($min_temp,1) . "&deg;C</b>"; 
echo "</br>Max temperature in interval: <b>" . number_format($max_temp,1) . "&deg;C</b>"; 
echo "</td></tr></table></td></tr></table>";

$query = "SELECT COUNT(*) AS count FROM readings"; // Check how many readings..
$result = mysqli_query($con, $query);
$row = mysqli_fetch_array($result);
echo "Plotted " . $num_plotted_times . " out of " . $row['count'];

echo ("</center>");
echo ("</body>");
echo ("</html>");

mysqli_close($con);

?>
Med den får jag detta utseendet:
(Nej, jag har inte sååå varmt här inne... Det måste vara denna tempsensorn som är trasig. I och för sig sitter den direkt på raspbarryn så det blir kanske lite varmare där men inte så mycket tycker jag.. Får se när jag kopplar in fler om de visar annorlunda!)
Bild

Nu har jag forwardat portarna och skaffat dynDNS hos noip.com så att jag kommer åt Raspberryn från internet.

Jag har också utvidgat både webinterfacet och androidappen så att jag kan styra en lysdiod samt att jag hela tiden får uppdaterad information om ifall pinnen är hög eller ej (så att man ser på appen tex om man släcker lysdioden från datorn).

Android appen hämtar data från ett XML-formaterat php dokument på servern (som laddas ned av en bakgrundsprocess). Det är även detta dokument som styr lysdioden genom GET dataöverföring.
Bild

PHP/XML dokumentet ser ut såhär:

Kod: Markera allt

<?php

// Set filetype to XML
header('Content-type: application/xml');


// Controll LED
if (isset($_GET['led']))
    $led = $_GET['led'];
else
    $led = "";
system('gpio -g mode 7 out'); // Set LED IO to output
if($led == "1")
    system('gpio -g write 7 1'); // Turn on LED
else if ($led == "0")
    system('gpio -g write 7 0'); // turn off LED
$readLed = "";
exec("gpio -g read 7", $readLed);
$strLed = implode('', $readLed);

// Open temperaturesensor
$file = '/sys/bus/w1/devices/10-0008014c61ed/w1_slave';
// Read all text
$text = file($file);
// get the temperature
$temp = explode('=',$text[1]);
$temp = number_format($temp[1] / 1000, 2, '.', '');

// Write XML Structure
$writer = new XMLWriter();  
$writer->openURI('php://output');   
$writer->startDocument('1.0','UTF-8'); 
$writer->startElement('records');  
    $writer->startElement('temperatureSensor');  
       $writer->writeAttribute('value', $temp);  
       $writer->writeAttribute('date', date('y-m-d', time()));  
       $writer->writeAttribute('time', date('H:i', time()));  
    $writer->endElement();   
    $writer->startElement('led');  
       $writer->writeAttribute('value', $strLed);
    $writer->endElement();   
$writer->endElement(); 
$writer->endDocument();   
$writer->flush(); 
?>
Vilket tex ger detta som output:

Kod: Markera allt

<records>
    <temperatureSensor value="27.63" date="14-06-21" time="21:01"/>
    <led value="1"/>
</records>
Programmeringen till telefonen ser ut som följande:

Kod: Markera allt

package com.example.hometemperature;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.graphics.PorterDuff;

public class MainActivity extends ActionBarActivity {
	
	private static final String TAG = "Home Temperature";
	
	public static final String SERVER_URL = "http://*******.noip.me/";
	public static final String QUERY_FILE = "temperatur.php";
	public static final String QUERY_URL = SERVER_URL + QUERY_FILE;
	
	LinearLayout container;
	Button updateBtn;
	Button ledOnBtn;
	Button ledOffBtn;
	TextView temp1Tv;
	TextView temp1Tv2;
	TextView ledTv;
	AsyncDownloader downloader;
	Bitmap bg;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	
        super.onCreate(savedInstanceState);
        
        container = new LinearLayout(this);
        container.setOrientation(LinearLayout.VERTICAL);
        container.setPadding(30, 30, 30, 30);
        container.setBackgroundResource(R.drawable.bg);
        
        updateBtn = new Button(this);
        updateBtn.setOnClickListener(updateBtnListener);
        updateBtn.setText("Update");
        
        ledOnBtn = new Button(this);
        ledOnBtn.setOnClickListener(ledOnBtnListener);
        ledOnBtn.setText("Turn on LED");
        
        ledOffBtn = new Button(this);
        ledOffBtn.setOnClickListener(ledOffBtnListener);
        ledOffBtn.setText("Turn off LED");

        temp1Tv = new TextView(this);
        temp1Tv.setText("");
        temp1Tv.setBackgroundColor(Color.WHITE);
        temp1Tv.setTextSize(35);
        
        temp1Tv2 = new TextView(this); 
        temp1Tv2.setText("");
        temp1Tv2.setBackgroundColor(Color.WHITE);
        temp1Tv2.setTextSize(25);
        
        ledTv = new TextView(this);
        ledTv.setText("LED Status...");
        ledTv.setBackgroundColor(Color.WHITE);
        ledTv.setTextSize(20);

        container.addView(updateBtn);
        container.addView(temp1Tv);   
        container.addView(temp1Tv2); 
        container.addView(ledOnBtn);
        container.addView(ledOffBtn);   
        container.addView(ledTv);     
        
        
        downloader = new AsyncDownloader();
		new Timer().scheduleAtFixedRate(update, 10, 2000);
        
        setContentView(container);
        
       
    }
    
    TimerTask update = new TimerTask(){ // If timer interrupted, execute update if not already in progress.
		@Override
		public void run() {
			if (downloader.getStatus() != AsyncTask.Status.RUNNING){
				downloader = new AsyncDownloader(); // A task can only be executed one...
				downloader.execute("");
			}
		}
    };
    
    View.OnClickListener updateBtnListener = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
			if (downloader.getStatus() != AsyncTask.Status.RUNNING){
				downloader = new AsyncDownloader(); // A task can only be executed one...
				downloader.execute("");
			}
        }
    };

    View.OnClickListener ledOnBtnListener = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
			downloader = new AsyncDownloader(); // A task can only be executed one...
			downloader.execute("?led=1");
        }
    };
    
    View.OnClickListener ledOffBtnListener = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
			downloader = new AsyncDownloader(); // A task can only be executed one...
			downloader.execute("?led=0");
        }
    };
    
    private class AsyncDownloader extends AsyncTask<String, String, Integer> {

		@Override
		protected Integer doInBackground(String... params) {
			XmlPullParser receivedData = tryDownloadingXmlData(params[0]);
			int recordsFound = tryParsingXmlData(receivedData);
			return recordsFound;
		}

		private XmlPullParser tryDownloadingXmlData(String query) {
			try {
				URL xmlUrl = new URL(QUERY_URL + query);
				XmlPullParser receivedData = XmlPullParserFactory.newInstance().newPullParser();
				receivedData.setInput(xmlUrl.openStream(), null);
				return receivedData;
			} catch (XmlPullParserException e) {
				Log.e(TAG, "tryDownloadingXmlData Exception:", e);				
			} catch (IOException e) {
				Log.e(TAG, "tryDownloadingXmlData Exception:", e);				
			}
			return null;
		}
		
		private int tryParsingXmlData(XmlPullParser receivedData) {
			if (receivedData != null){
				try {
					return processReceivedData(receivedData);
				} catch (XmlPullParserException e) {
					Log.e(TAG, "tryParsingXmlData Exception:", e);				
				} catch (IOException e) {
					Log.e(TAG, "tryDownloadingXmlData Exception:", e);				
				}
			}
			return 0;
		}

		private int processReceivedData(XmlPullParser receivedData) throws XmlPullParserException, IOException {
			int eventType = -1;
			int recordsFound = 0;
			
			// Find values in the XML records
			String value = "";
			String date = "";
			String time = "";
			
			while (eventType != XmlResourceParser.END_DOCUMENT) {
				String tagName = receivedData.getName();
				
				switch (eventType) {
				case XmlResourceParser.START_TAG:
					if (tagName.equals("temperatureSensor")){
						value = receivedData.getAttributeValue(null, "value");
						date = receivedData.getAttributeValue(null, "date");
						time = receivedData.getAttributeValue(null, "time");
					}
					if (tagName.equals("led")){
						value = receivedData.getAttributeValue(null, "value");
					}
					break;
				case XmlResourceParser.END_TAG:
					if (tagName.equals("temperatureSensor")){
						//Log.i(TAG, "Data: " + value + date + time );
						recordsFound ++;
						publishProgress(value, date, time); // Send values to the main thread.
					}
					if (tagName.equals("led")){
						recordsFound ++;
						publishProgress(value);
					}
					break;
				}
				eventType = receivedData.next();
			}
			if (recordsFound == 0) {
				publishProgress();
			}
			return recordsFound;
		}	

		@Override
		protected void onProgressUpdate(String... values) {
			if (values.length == 0) {
				Log.i(TAG, "No data downloaded");
			} if (values.length == 3){
				String value = values[0];
				String date = values[1];
				String time = values[2];
				
				temp1Tv.setText(value + (char) 0x00B0 + "C");
				temp1Tv2.setText("Last update "  + time + " " + date);
			} else if (values.length == 1){
				ledTv.setText("Led status: " + values[0]);
			}
			
			super.onProgressUpdate(values);
		}		   	
    }
    
    public static Bitmap getBitmapFromAsset(Context context, String filePath) {
        AssetManager assetManager = context.getAssets();

        InputStream istr;
        Bitmap bitmap = null;
        try {
            istr = assetManager.open(filePath);
            bitmap = BitmapFactory.decodeStream(istr);
        } catch (IOException e) {
            Log.e(TAG, "EXCEPTION ON LOAD BITMAP", e);
        }

        return bitmap;
    }
}
Mer framsteg kommer förhoppningsvis snart!

Mvh. Daniel
Användarvisningsbild
Electricguy
Inlägg: 12480
Blev medlem: 15 augusti 2007, 16:52:14
Ort: Kälmä' typ..

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av Electricguy »

Fräsigt värre! :D
Användarvisningsbild
tecno
Inlägg: 27248
Blev medlem: 6 september 2004, 17:34:45
Skype: tecnobs
Ort: Sparreholm, Södermanland N 59° 4.134', E 16° 49.743'
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av tecno »

Detta följs med intresse
Användarvisningsbild
MicaelKarlsson
Inlägg: 4669
Blev medlem: 18 juni 2004, 09:16:07
Ort: Aneby
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av MicaelKarlsson »

Tjusigt!

Delar är väldigt intressanta, egentligen allt utom det där med telefonen intresserar mig mycket. Så tack för information, kod och inspiration.

Följs med stort intresse.

Lycka till!! :tumupp:
Zkronk
Inlägg: 1439
Blev medlem: 23 augusti 2005, 16:44:36
Ort: Uppsala

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av Zkronk »

Vart lagrar du databasen? Vad jag har läst så är SQL-databaser som nyttjas flitigt på minneskort rena döden för minneskort pga. begränsat antal skrivningar.
Med temploggning med 2-minuters intervall så blir det ju ganska frekvent skrivande till lagringsmediet.
Användarvisningsbild
Kulla
Inlägg: 1325
Blev medlem: 7 januari 2010, 10:06:11
Ort: Sandared
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av Kulla »

Intressant. Jag tänkte göra samma med iPhone.
Användarvisningsbild
squiz3r
Inlägg: 5424
Blev medlem: 5 september 2006, 20:06:22
Ort: Lund
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av squiz3r »

Kul med intresse!

Zkronk: Ajdå, det har jag inte alls tänkt på men det låter ju rätt oroväckande nu när du säger det.. Jag kollade runt lite snabbt på internet och det finns många som är rädda för det och spekulerar runt det, men även många som påstår att det inte är några problem. Tydligen verkar det som att minneskortet sprider ut datan över alla zoner på minneskortet för att de skall slitas jämnt och då skall det vara mindre risk om man har stort minneskort (jag kör med 16 gig). Jag hittade i alla fall ingen som kunde bekräfta att det hade hänt. Men jag skall kolla runt mer sen!

Sitter och leker med det trådlösa nu! Billiga RX433N sändare och TX433 från kjell och company. Men jösses vad mycket skräp jag får in på mottagaren när inget sänder...
Bild
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av blueint »

Hur ser skräpet från RX433N ut? och vad slags område är det? hyreshus, radhus, ghetto, villor, studentområde?

Lite synd om ytterliggare ett band har lidit av allmänningarnas destruktion.
xxargs
Inlägg: 10189
Blev medlem: 23 september 2006, 14:28:27
Ort: Södertälje

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av xxargs »

Modernare SD/USB-minnen så sprids skrivningarna på alla block i tur och ordning så att alla block slits jämt (vilket innebär att redan skriven data flyttas också fysiskt och reallokeras till samma adress som tidigare)

Dock moderna multinivå-celler som finns i dagens många GB-minnen kanske tål runt 1000 omskrivningar (mot tidigare 10000 för dubbelnivå-celler och singelnivåceller 100000 ggr) innan någon cell i blocket börja koda fel - i början upptäcks och rättas av ECC med reallokering till andra lediga minnesblock och reservblock men till sist så har man kört igenom samtliga block och allt fler håller inte data och man börja få läsfel.

Hur det beter sig utåt mot OS om man kommer så långt är okänt då man i flesta fallen har tjänat ut utrustningen innan sådana effekter visar sig.

Tyvärr går det inte plocka ut lika mycket information ang 'wear' som i en SSD-disk och algoritmerna är heller inte lika avancerade som i en SSD. och tyvärr går det heller inte att skicka 'trim' till dom flesta USB/SD-minnen även om man börja fundera på det.

Att tänka på att även om det är en byte som skrivs i tex. en databas, så är det minst en sektor på 512 Byte som skrivs, och sedan är sektorerna samlade i block om 32-128 kB varav allihopa måste flyttas till annat block om blocket skall raderas.

Till detta beror det på minneskontrollern i minnet hur vida den hanterar skrivning till samma sektor upprepande - om det skrivs en ny block var gång eller om denna sektor får sin egen block och kan skriva samtliga sektorer på denna innan det flyttas till nästa lediga block.

idag kosta 8 GB SD under 50 kronor så egentligen skulle man prova att våldskriva till samma sektor med olika slumptal eller uppräkning och läsa tillbaka igen så fort som möjligt och se hur länge det klarar sig innan det blir läsfel - dvs. om det handlar om dagar, veckor, månader eller år och om det bara är en sektor eller om hela minnet börja uppvisa fel samtidigt (dvs. alla block är utslitna)...
Användarvisningsbild
squiz3r
Inlägg: 5424
Blev medlem: 5 september 2006, 20:06:22
Ort: Lund
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av squiz3r »

blueint: Det är radhusområde. Kan försöka ta bild på skräpet sen, det är lite varierande, ibland inget och ibland ganska mycket. Men de här billiga mottagarna, tar de inte emot lite allt möjligt från alla möjliga frekvensband?

Tydligen kan man inte alltid ha en bra dag.. Jag började med att skriva ett program till PIC12F629 som kunde styra mina NEXA fjärrströmbrytare. När jag var klar med det kraschade labbdatorn så jag får inte tag på filen längre. Istället för att börja om började jag fundera på om det kunde gå att styra radiosändaren direkt från Raspbarryn. Efter att jag laddat ner wiringpis pluggin till python så var det inga problem att hinna med pulserna tillräckligt snabbt, dock som jag misstänkte så var det ju andra processer som avbröt ibland så några gånger då och då blev det delay på kanske 1 mS istället för 0.250mS så det gick inte. Trots detta satt jag hela dagen och testade olika metoden, satte högre prioritet på mitt script och utförde alla möjliga sorters tidsräkningar men det gick inte så nu återgår jag till en PIC som får kommunicera med Raspberryn i ett protokoll där tiden inte är en viktig faktor.

Jag har också börjat uppleva problem med raspberryn, två gånger har den helt plötsligt startat om när jag använder den och tangentbordet fungerar knappt på den längre.. Den får med kanske två tredjedelar av det man skriver.. Skulle detta kunna vara på grund av utslitet minneskort? De första dygnen tog jag tempmätning var 10'e sekund för att få lite data att arbeta med så totalt har jag nog skrivit in ca 30-40 tusen mätningar till databasen. Kan man undersöka minneskortet på något sätt?

Tror jag skall ta och köra med en mySQL databas på mitt webhotell istället så slipper man så många skrivningar på minneskortet.

// Daniel
Zkronk
Inlägg: 1439
Blev medlem: 23 augusti 2005, 16:44:36
Ort: Uppsala

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av Zkronk »

Hur är det med strömförsörjningen?
Har du en av de tidiga versionerna som har usb-portarna avsäkrade till 100mA med sk. "polyfuses"?
På lite senare modeller av korten så har de bytt ut de mot 0 Ohm-resistorer just för att minska problemen när man kopplar in lite mer strömkrävande tillbehör.
Ett vanligt usb-tangentbords strömförbrukning ligger väl iofs oftast ganska precis på max 100mA..

Sen har jag läst att det är för liten kapacitans på avkopplingskondensatorerna på usb-portarna (mindre än vad standarden säger), vilket gör att det är lätt hänt att det blir en spännings-dip när man kopplar in en usb-enhet, vilket gör att den startar om. Men har du inte kopplat in någon enhet i samband med hängning/dylikt så är nog inte det problemet.

Lite vilda spekulationer bara, kanske kan vara till någon nytta :)
Användarvisningsbild
squiz3r
Inlägg: 5424
Blev medlem: 5 september 2006, 20:06:22
Ort: Lund
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av squiz3r »

Att hitta revision number var ju inte helt lätt, man kunde ju trott att det skulle stå på kortet, men icke.. Men det står i alla fall att det är byggt vecka 11 år 2014. Sen har det två monteringshål och blå ljudutgång, så då borde det vara rev 2?

Om jag kör "cat /proc/cpuinfo" så får jag:

Kod: Markera allt

processor       : 0
model name      : ARMv6-compatible processor rev 7 (v6l)
Features        : swp half thumb fastmult vfp edsp java tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xb76
CPU revision    : 7

Hardware        : BCM2708
Revision        : 000e
Serial          : 00000000ad6a70f5
Problemen uppstod inte när jag satte i tangentbordet, utan de satt i hela tiden. Sen är det trådlöst tangentbord och mus, det borde nästan ta mindre ström (i och med att både tangentbord och mus är batteridrivna) men det kanske blir mer störningar på spänningsmatningen å andra sidan.. Har tyvärr inget annat t-bord med USB som jag kan testa med.

Det kan ju ha varit nått av mina script som körs i bakgrunden som gjorde nått dumt också..
Zkronk
Inlägg: 1439
Blev medlem: 23 augusti 2005, 16:44:36
Ort: Uppsala

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av Zkronk »

Det är F1 och F2 som sitter precis bredvid USB-portarna som jag pratar om..
Sitter det 000-resistorer på dessa så är inte problemet där i alla fall :)
Användarvisningsbild
squiz3r
Inlägg: 5424
Blev medlem: 5 september 2006, 20:06:22
Ort: Lund
Kontakt:

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av squiz3r »

F1 på mitt kretskort sitter vid microUSB-kontakten, och ser ut såhär: (Tror det är 1,5A)
Bild

F1 och F2 som verkar ha suttit på ovansidan mellan audiokontakten och USB-kontakterna finns inte på min, där sitter bara en kondensator.

Eventuellt kan det vara min radiosändare som leder till problemet med omstart, trots att den ligger på 5v linan.. Skall testa sätta en större kondensator till den (kör bara 0.33µF elektrolyt + en keramisk).

Anledningen till att t-bordet klöddar är ju dock fortfarande ett mysterium..

----

Nu kan jag styra 20 nexa/anslut-mottagare från telefonen (och internet).
Screenshot_2014-06-27-11-26-03.png
På samma sätt som innan så skickar jag datan som GET till xml/php-filen. Denna lägger dels in det i en databas så att jag har koll på senaste läget och sen skickar den det till ett pythonscript som skickar ut en seriell signal på en datapinne och en klockpinne till PIC-processorn som i sin tur skickar det via 433Mhz. Protokollet mellan raspberry och PIC är ett långsamt protokoll som är nästan helt tidsoberoende på grund av klocksignalen. Först skickas en startbit, sen skickas 20 databitar som talar om ifall var sensor skall vara på eller av och efter det 20 databitar som talar om ifall det ska skickas ett kommando till var mottagare. Pythonfilen behöver ha root-access för att komma åt GPIO så därför var jag tvungen att lägga in WWW-data (apaches användare) i sudoers-filen så att den har tillåtelse att köra (enbart) detta skriptet med sudo-rättighet utan lösenord. Detta görs genom att öppna sudo-filen med kommandot:
sudo visudo
och lägga till kommandot i slutet:
www-data ALL=(ALL) NOPASSWD: /usr/bin/python /home/pi/gpioaccess/*
(Detta ger apache rätten att köra alla pythonscript i katalogen gpioaccess med sudo-rättighet)

Pytonscriptet ser ut som följande och vill ha 40 argument som indata, 20 on/off och sen 20 send/don't send:

Kod: Markera allt

#!/usr/bin/env python

import time # For wait
import wiringpi # For GPIO
import sys # For arguments in script call

# Check if there is 40 arguments passed (+ the path)
if len(sys.argv) != 41:                                       # Exit script if it isn't
    print "Wrong number of arguments (" + str(len(sys.argv)-1) + ")" # 40 args (41 including path)
    raise SystemExit    

DATAPIN = 24
CLKPIN = 23

io = wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_GPIO)

io.pinMode(DATAPIN,io.OUTPUT)
io.pinMode(CLKPIN,io.OUTPUT)

io.digitalWrite(DATAPIN,io.LOW)
io.digitalWrite(CLKPIN,io.LOW)


def sendStart():
    io.digitalWrite(DATAPIN, io.HIGH)       # Set datapin high
    io.delayMicroseconds(10000)             # Leave high for 10mS

def sendBit(value):
    if (value == 0):       
        io.digitalWrite(DATAPIN, io.LOW)    # Set datapin low
    else:       
        io.digitalWrite(DATAPIN, io.HIGH)   # Set datapin high
    io.delayMicroseconds(100)               # Wait 100 uS    
    io.digitalWrite(CLKPIN, io.HIGH)        # Clock in data..
    io.delayMicroseconds(1000)              # Wait 1 mS
    io.digitalWrite(CLKPIN, io.LOW)         # Set clk low
    io.digitalWrite(DATAPIN, io.LOW)        # set data low

#Check so all arguments are eather "1" or "0"
i =  1 # Start after path
while i <= 40:
    if sys.argv[i] != "1" and sys.argv[i] != "0":
        print "Wrong argument value: " + sys.argv[i]
        raise SystemExit
    i += 1

# Send data
sendStart() # Send startbit
i = 1 # Start after path
while i <= 40: # Send data (arguments)
    sendBit(int(sys.argv[i]))
    i += 1

# Done!
print("Sucess")
Php-filen som tar emot GET-data, lägger in det i databasen och startar pythonscriptet:

Kod: Markera allt

<?php

// Set filetype to XML
header('Content-type: application/xml');

function getData(){
    // Read GET-data
    global $led; // Read LED data
    $led = "";
    if (isset($_GET['led']))
        $led = $_GET['led'];
        
    global $nexa;   // Read individual data for nexa receivers
    for($i = 0; $i<20;$i++){
        $nexa[$i] = "";
        if (isset($_GET['nexa' . (string)$i]))
            $nexa[$i] = $_GET['nexa' . (string)$i];   
    } 
    if (isset($_GET['allNexa'])){ // Read group command for all 20 nexa devices (This will override indivudual data)
        $allNexa = $_GET['allNexa'];
        for($i = 0; $i<20;$i++){
            $nexa[$i] = $allNexa;
        }
    }  
}

function execData($nexa){
    // Controll LED    
    global $led;
    system('gpio -g mode 7 out'); // Set LED IO to output
    if($led == "1")
        system('gpio -g write 7 1'); // Turn on LED
    else if ($led == "0")
        system('gpio -g write 7 0'); // turn off LED
    $readLed;
    exec("gpio -g read 7", $readLed);
    global $strLed;
    $strLed = implode('', $readLed);
    
    // Controll nexa equipment
    global $msg;
    global $con;
    $onOffStr = "";
    $sendDontStr = "";
    for ($i = 0; $i<20;$i++){
        $onOffStr .= ($nexa[$i] == "")?" 0":" ".$nexa[$i]; // If empty, send something to PIC.
        $sendDontStr .= ($nexa[$i] == "")?" 0":" 1"; // If string empty, then don't send anything to receiver..
        if ($nexa[$i]!=""){ // Insert values to database
            $queryStr = "REPLACE INTO nexa VALUES (" . $nexa[$i] . ", " . $i . ")";
            $msg .= mysqli_query($con, $queryStr);
        }
    }
    $cmd = escapeshellcmd('sudo python /home/pi/gpioaccess/nexaPicControll.py' . $onOffStr . $sendDontStr); // gpioacess is in sudoers with no password
    exec($cmd, $msgArray1);
}

// Read GET-data
$led;
$nexa;
getData();  
// Execute data
$strLed = "";
$msg = "";
$con = mysqli_connect('localhost', '***', '***', 'sensors');
if (mysqli_connect_errno()) {
    $msg = "Failed to connect to mysql: " .  mysqli_connect_errno();
}
execData($nexa);

// Open temperaturesensor
$file = '/sys/bus/w1/devices/10-0008014c61ed/w1_slave';
// Read all text
$text = file($file);
// get the temperature
$temp = explode('=',$text[1]);
$temp = number_format($temp[1] / 1000, 2, '.', '');

// Write XML Structure
$writer = new XMLWriter();  
$writer->openURI('php://output');   
$writer->startDocument('1.0','UTF-8'); 
$writer->startElement('records');  
    $writer->startElement('temperatureSensor');  
    	$writer->writeAttribute('value', $temp);  
    	$writer->writeAttribute('date', date('y-m-d', time()));  
    	$writer->writeAttribute('time', date('H:i', time()));  
    $writer->endElement();   
    $writer->startElement('led');  
    	$writer->writeAttribute('value', $strLed);
    $writer->endElement();   
    $writer->startElement('scriptMsg');  
    	$writer->writeAttribute('value', $msg);
    $writer->endElement();
    $queryStr = "SELECT * FROM nexa";
    $rows = mysqli_query($con, $queryStr);
    $writer->startElement('nexa');
    while ($row = mysqli_fetch_array($rows)){
            $writer->startElement('nexa' . $row['unit']);
                $writer->writeAttribute('state', $row['value']);
            $writer->endElement(); 
    }  
    $writer->endElement();   
$writer->endElement(); 
$writer->endDocument();   
$writer->flush(); 

mysqli_close($con);
?>
Programmet i telefonen skickar data till php-filen men läser också av senast skickad information från samma php/xml-fil så att läget på knapparna alltid är rätt när man startar appen (eller om man slår på/av någon mottagare via datorn)

Kod: Markera allt

package com.example.hometemperature;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Point;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) public class MainActivity extends ActionBarActivity {
	
	private static final String TAG = "Home Temperature";
	
	public static final String SERVER_URL = "http://****.noip.me/";
	public static final String QUERY_FILE = "temperatur.php";
	public static final String QUERY_URL = SERVER_URL + QUERY_FILE;

	public static final int CURRENT_VIEW_HOME = 0;
	public static final int CURRENT_VIEW_TEMP = 1;
	int currentView;
	Display display;
    Point displaySize;
	// On home view
	ScrollView scrollViewHome; // First screen (Light control)
	LinearLayout viewHome; 
	List<LinearLayout> viewHomeButtonRows;
	Button switchToTemp; // Change view from home to temp
	List<OnOffButton> nexaBtn;
	// On temperature view
	LinearLayout viewTemp; // other screen, temperature
	Button switchToHome;
	Button updateBtn;
	Button ledOnBtn;
	Button ledOffBtn;
	TextView temp1Tv;
	TextView temp1Tv2;
	TextView ledTv;
	AsyncDownloader downloader;
	Timer tempUpdateTimer;
	Bitmap bg;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	
        super.onCreate(savedInstanceState);
        
        display = getWindowManager().getDefaultDisplay();
        displaySize = new Point();
        display.getSize(displaySize);

        setUpHome(); // Set up all things on first screen
        setUpTemp(); // Set up all things on the temperature view
        
        currentView = CURRENT_VIEW_HOME;
        setContentView(scrollViewHome);
    }
    
    private void setUpHome(){
    	scrollViewHome = new ScrollView(this);
        scrollViewHome.setBackgroundResource(R.drawable.tagme_tree);
    	
        viewHome = new LinearLayout(this);
        viewHome.setOrientation(LinearLayout.VERTICAL);
        viewHome.setPadding(30, 30, 30, 30);
    	scrollViewHome.addView(viewHome);
        
        switchToTemp = new Button(this);
        switchToTemp.setOnClickListener(switchToTempView);
        switchToTemp.setText("Temperature view");
        viewHome.addView(switchToTemp);
        
        String[] buttonTexts = {"Window light",
        						"TV lights",
        						"Reading light",
        						"Nexa 4",
        						"Nexa 4",
        						"Nexa 5",
        						"Nexa 6",
        						"Nexa 7",
        						"Nexa 8",
        						"Nexa 9",
        						"Nexa 10",
        						"Nexa 11",
        						"Nexa 12",
        						"Nexa 13",
        						"Nexa 14",
        						"Nexa 15",
        						"Nexa 16",
        						"Nexa 17",
        						"Nexa 18",
        						"Nexa 19"};
        viewHomeButtonRows = new ArrayList<LinearLayout>();
        nexaBtn = new ArrayList<OnOffButton>();
        for (int j = 0; j<(buttonTexts.length/4+0.99);j++){
        	LinearLayout view = new LinearLayout(this);
            view.setOrientation(LinearLayout.HORIZONTAL);
        	viewHome.addView(view);
        	viewHomeButtonRows.add(view);
	        for (int i = 0; i < 4 && j*4+i < buttonTexts.length; i++){
	        	int index = j*4+i;
	        	OnOffButton b = new OnOffButton(this);
	        	b.setText("Turn off " + buttonTexts[index], "Turn on " + buttonTexts[index]);
	        	b.setId(index);
	        	b.setTextSize(10f);
	        	b.setTextColor(Color.parseColor("#e0e0e0"));
	        	b.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL);
	        	b.setLayoutParams(new LinearLayout.LayoutParams(displaySize.x/5,displaySize.x/5, 0.25f));
	        	b.setOnClickListener(new nexaBtnListener(index));
	        	nexaBtn.add(b);
	        	view.addView(b);
	        }
        }
        // Get the states of the nexa-buttons
		downloader = new AsyncDownloader();
		downloader.execute("");
    }
    
    private void setUpTemp(){
        viewTemp = new LinearLayout(this);
        viewTemp.setOrientation(LinearLayout.VERTICAL);
        viewTemp.setPadding(30, 30, 30, 30);
        viewTemp.setBackgroundResource(R.drawable.bg);
        
        switchToHome = new Button(this);
        switchToHome.setOnClickListener(switchTohomeView);
        switchToHome.setText("Home");
        
        updateBtn = new Button(this);
        updateBtn.setOnClickListener(updateBtnListener);
        updateBtn.setText("Update");
        
        ledOnBtn = new Button(this);
        ledOnBtn.setOnClickListener(ledOnBtnListener);
        ledOnBtn.setText("Turn on LED");
        
        ledOffBtn = new Button(this);
        ledOffBtn.setOnClickListener(ledOffBtnListener);
        ledOffBtn.setText("Turn off LED");

        temp1Tv = new TextView(this);
        temp1Tv.setText("");
        temp1Tv.setBackgroundColor(Color.WHITE);
        temp1Tv.setTextSize(35);
        
        temp1Tv2 = new TextView(this); 
        temp1Tv2.setText("");
        temp1Tv2.setBackgroundColor(Color.WHITE);
        temp1Tv2.setTextSize(25);
        
        ledTv = new TextView(this);
        ledTv.setText("LED Status...");
        ledTv.setBackgroundColor(Color.WHITE);
        ledTv.setTextSize(20);

        viewTemp.addView(switchToHome);
        viewTemp.addView(updateBtn);
        viewTemp.addView(temp1Tv);   
        viewTemp.addView(temp1Tv2); 
        viewTemp.addView(ledOnBtn);
        viewTemp.addView(ledOffBtn);   
        viewTemp.addView(ledTv);  	
        
        tempUpdateTimer = new Timer();
		tempUpdateTimer.scheduleAtFixedRate(update, 10, 10000);
    }
    
    TimerTask update = new TimerTask(){ // If timer interrupted, execute update if not already in progress.
		@Override
		public void run() {
			if (downloader.getStatus() != AsyncTask.Status.RUNNING){
				downloader = new AsyncDownloader(); // A task can only be executed one...
				downloader.execute("");
			}
		}
    };
    
    public class nexaBtnListener implements OnClickListener{

    	int nexaId;
    	public nexaBtnListener(int nexaId){
    		this.nexaId = nexaId;
    	}
    	
		@Override
		public void onClick(View v) {
			if (nexaBtn.get(nexaId).getState()){
				downloader = new AsyncDownloader(); // A task can only be executed one...
				downloader.execute("?nexa" + Integer.toString(nexaId) + "=0");
				nexaBtn.get(nexaId).setState(false);
			}
			else{
				downloader = new AsyncDownloader(); // A task can only be executed one...
				downloader.execute("?nexa" + Integer.toString(nexaId) + "=1");
				nexaBtn.get(nexaId).setState(true);
			}
		}
    	
    }
    
    View.OnClickListener switchToTempView = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
        	currentView = CURRENT_VIEW_TEMP;
			setContentView(viewTemp);
        }
    };     
    
    View.OnClickListener switchTohomeView = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
        	currentView = CURRENT_VIEW_HOME;
			setContentView(scrollViewHome);
			downloader = new AsyncDownloader(); // Get the states of the nexa-buttons
			downloader.execute("");
        }
    };   
    
    View.OnClickListener updateBtnListener = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
			if (downloader.getStatus() != AsyncTask.Status.RUNNING){
				downloader = new AsyncDownloader(); // A task can only be executed one...
				downloader.execute("");
			}
        }
    };

    View.OnClickListener ledOnBtnListener = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
			downloader = new AsyncDownloader(); // A task can only be executed one...
			downloader.execute("?led=1");
        }
    };
    
    View.OnClickListener ledOffBtnListener = new View.OnClickListener() { // If button was clicked, execute update if not already in progress.
        @Override
        public void onClick(View v) {
			downloader = new AsyncDownloader(); // A task can only be executed one...
			downloader.execute("?led=0");
        }
    };
    
    private class AsyncDownloader extends AsyncTask<String, String, Integer> {

		@Override
		protected Integer doInBackground(String... params) {
			XmlPullParser receivedData = tryDownloadingXmlData(params[0]);
			int recordsFound = tryParsingXmlData(receivedData);
			return recordsFound;
		}

		private XmlPullParser tryDownloadingXmlData(String query) {
			try {
				URL xmlUrl = new URL(QUERY_URL + query);
				XmlPullParser receivedData = XmlPullParserFactory.newInstance().newPullParser();
				receivedData.setInput(xmlUrl.openStream(), null);
				return receivedData;
			} catch (XmlPullParserException e) {
				Log.e(TAG, "tryDownloadingXmlData Exception:", e);				
			} catch (IOException e) {
				Log.e(TAG, "tryDownloadingXmlData Exception:", e);				
			}
			return null;
		}
		
		private int tryParsingXmlData(XmlPullParser receivedData) {
			if (receivedData != null){
				try {
					return processReceivedData(receivedData);
				} catch (XmlPullParserException e) {
					Log.e(TAG, "tryParsingXmlData Exception:", e);				
				} catch (IOException e) {
					Log.e(TAG, "tryDownloadingXmlData Exception:", e);				
				}
			}
			return 0;
		}

		private int processReceivedData(XmlPullParser receivedData) throws XmlPullParserException, IOException {
			int eventType = -1;
			int recordsFound = 0;
			
			// Find values in the XML records
			String value = "";
			String date = "";
			String time = "";
			String unit = "";
			
			while (eventType != XmlResourceParser.END_DOCUMENT) {
				String tagName = receivedData.getName();
				
				switch (eventType) {
				case XmlResourceParser.START_TAG:
					if (tagName.equals("temperatureSensor")){
						value = receivedData.getAttributeValue(null, "value");
						date = receivedData.getAttributeValue(null, "date");
						time = receivedData.getAttributeValue(null, "time");
					}
					if (tagName.equals("led")){
						value = receivedData.getAttributeValue(null, "value");
					}
					if (tagName.matches("nexa[0-9][0-9]?")){
						value = receivedData.getAttributeValue(null, "state");
						unit = tagName;
					}
					break;
				case XmlResourceParser.END_TAG:
					if (tagName.equals("temperatureSensor")){
						recordsFound ++;
						publishProgress(value, date, time); // Send values to the main thread.
					}
					if (tagName.equals("led")){
						recordsFound ++;
						publishProgress(value);
					}
					if (tagName.matches("nexa[0-9][0-9]?")){
						recordsFound ++;
						publishProgress(value, unit);
					}
					break;
				}
				eventType = receivedData.next();
			}
			if (recordsFound == 0) {
				publishProgress();
			}
			return recordsFound;
		}	

		@Override
		protected void onProgressUpdate(String... values) {
			if (values.length == 0) {
				Log.i(TAG, "No data downloaded");
			} if (values.length == 3){
				String value = values[0];
				String date = values[1];
				String time = values[2];
				
				temp1Tv.setText(value + (char) 0x00B0 + "C");
				temp1Tv2.setText("Last update "  + time + " " + date);
			} else if (values.length == 1){
				ledTv.setText("Led status: " + values[0]);
			} else if (values.length == 2){
				String value = values[0];
				String unit = values[1];
				Log.i(TAG, "Download nexa:" + value);
				int number = -1;
				if (unit.matches("nexa[0-9]")){ // Only one digit
					number = Integer.parseInt(unit.substring(unit.length() - 1));
				} else if (unit.matches("nexa[0-9]{2}")) { // Two diggits
					number = Integer.parseInt(unit.substring(unit.length() - 2));
				}
				Log.i(TAG, "Setting button" + Integer.toString(number));
				if (value.equals("0")){
					nexaBtn.get(number).setState(false); // Set state of button
				} else {
					nexaBtn.get(number).setState(true);
				}
			}
			
			super.onProgressUpdate(values);
		}		   	
    }
    
    public static Bitmap getBitmapFromAsset(Context context, String filePath) {
        AssetManager assetManager = context.getAssets();

        InputStream istr;
        Bitmap bitmap = null;
        try {
            istr = assetManager.open(filePath);
            bitmap = BitmapFactory.decodeStream(istr);
        } catch (IOException e) {
            Log.e(TAG, "EXCEPTION ON LOAD BITMAP", e);
        }

        return bitmap;
    }
}
Ni får ha överseende med ful kod, den blir snyggare senare i projektets gång!

Mvh. Daniel
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
nifelheim
Den första
Inlägg: 2487
Blev medlem: 27 mars 2008, 22:31:16
Ort: stockholm

Re: Squiz3rs hemautomation med egen androidapp och Raspberry

Inlägg av nifelheim »

snyggt :bravo:

mät spänningen på stiftlisten (vid GPIO pinnarna) med allt inkopplat ,
om 5 volten bara är 4,7 där så får du hitta på nåt :)

nu vet jag inte exakt hur ditt 1-wire nätverk ser ut,
men att ta en GPIO pinne direkt på CPU'n (SOC idetta fall :) )
och dra runt den flera meter i huset, är lite taskigt.

GPIO pinnarna har nästan inget skydd alls mot störningar ESD osv
du leder spikarna rakt i på kislet, inte optimalt för långtidstabilitet,
om jag uttrycker det lite snällt :wink:

stoppa dit en drivkrets och ett störskydd, bygg själv eller köp färdiga.
finns massor med appnötter på Maxims hemsida.
Skriv svar