Hemautomation V2
Hemautomation V2
I mitt förra hemautomationsprjekt styrde jag mina trådlösa NEXA kontakter med en Raspberry Pi och en PIC med radiosändare samt en app till telefonen. Det hela fungerade hyfsat med var lite ruffigt byggt så jag tänkte börja om från scratch nu.
Jag började med att köpa en ny Raspberry Pi, denna gången modell 2 som har fyrkärnig processor tillsammans med en hel del andra uppgraderingar. Köpte den på Kjell för att få den som är tillverkad i UK. Finns att tillgå på DX men det är bara en 50-lapp som skiljer så det priset kan det vara värt. Innan de intressanta delarna kan börja så skall jag få en order från DX med arduino, radiosändare och lite annat skoj. Under tiden började jag med belysningen i mitt vardagsrum. Jag har för tillfället två lampor, en plafond och en takkrona men båda går på samma brytare. Detta löste jag genom att sätta trådlösa nexa mottagare på dem.
Började med julas billiga mottagare för vägguttag. Plockade ur kretskortet och skruvade fast i en kopplingsdosa från biltema. Helt perfekt passform. Efter ett tag blev det dock trassligt med alla sladdar och jag bestämde mig för att överge denna designen och övergå till en dimmer för takkronan. En fjärrdimmer från Anslut för 49kr på jula samt en fjärrströmbrytare från NEXA (169kr) införskaffades. Båda för fast installation. Dessa skruvades sedan fast på toppen av plafonden (som förövrigt också är Jula, 49kr). Nexas brytare var betydligt tunnare så jag satte en plastbit som distans så att de fick samma höjd. Sedan räcker det med en lång skruv från lampan in i taket så ligger lampan platt på fjärrströmbrytarna. Lite kabeldragning... På plats i taket Väggströmbrytaren skruvades loss och kablarna skarvedes i en skarvdosa. Behöver bara slipa och lägga på ny färg runt om.. Äntligen kan jag ha lite stämningsbelysning i taket. Mer kommer förhoppningsvis snart.
Jag började med att köpa en ny Raspberry Pi, denna gången modell 2 som har fyrkärnig processor tillsammans med en hel del andra uppgraderingar. Köpte den på Kjell för att få den som är tillverkad i UK. Finns att tillgå på DX men det är bara en 50-lapp som skiljer så det priset kan det vara värt. Innan de intressanta delarna kan börja så skall jag få en order från DX med arduino, radiosändare och lite annat skoj. Under tiden började jag med belysningen i mitt vardagsrum. Jag har för tillfället två lampor, en plafond och en takkrona men båda går på samma brytare. Detta löste jag genom att sätta trådlösa nexa mottagare på dem.
Började med julas billiga mottagare för vägguttag. Plockade ur kretskortet och skruvade fast i en kopplingsdosa från biltema. Helt perfekt passform. Efter ett tag blev det dock trassligt med alla sladdar och jag bestämde mig för att överge denna designen och övergå till en dimmer för takkronan. En fjärrdimmer från Anslut för 49kr på jula samt en fjärrströmbrytare från NEXA (169kr) införskaffades. Båda för fast installation. Dessa skruvades sedan fast på toppen av plafonden (som förövrigt också är Jula, 49kr). Nexas brytare var betydligt tunnare så jag satte en plastbit som distans så att de fick samma höjd. Sedan räcker det med en lång skruv från lampan in i taket så ligger lampan platt på fjärrströmbrytarna. Lite kabeldragning... På plats i taket Väggströmbrytaren skruvades loss och kablarna skarvedes i en skarvdosa. Behöver bara slipa och lägga på ny färg runt om.. Äntligen kan jag ha lite stämningsbelysning i taket. Mer kommer förhoppningsvis snart.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Hemautomation V2
Än har det inte hänt något tyvärr... Jag beställde lite delar från DX som sagt. Beställde från europe direct eftersom de skulle leverera på 5-7 dagar vilket kändes OK. Än har jag dock inte fått något eftersom allt tydligen var semesterstängt från 1-14 feb (kinesiskt nyår antar jag). Detta innebär att det kommer ta 19-21 dagar istället innan jag får mina delar. Inte lika kul..
Jag kopplade i alla fall in min nya Raspberry Pi 2 idag och installerade Raspian för att se att allt fungerade. Testade även så att Java fungerade. På senare år finns det ju äkta stöd för java i Raspian, rätt smidigt. Måste dock installera Eclipse eller nått, utvecklingsmiljöerna som var med var allt annat än kompetenta. Bara att vänta nu tills min WiFi adapter kommer.
Jag kopplade i alla fall in min nya Raspberry Pi 2 idag och installerade Raspian för att se att allt fungerade. Testade även så att Java fungerade. På senare år finns det ju äkta stöd för java i Raspian, rätt smidigt. Måste dock installera Eclipse eller nått, utvecklingsmiljöerna som var med var allt annat än kompetenta. Bara att vänta nu tills min WiFi adapter kommer.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Hemautomation V2
Kul projekt! Jag kör en Raspberry med FRXCom och Domoticz, har fullt upp ändå med att testa enheter och så, har en hel del prylar från Kina nu som funkar ihop med FRXCom med.
2 nyfikna frågor!
När du har kört 2st devicer brevid varandra som i lådan där, får du inte problem med att den bommar ofta då? Jag kan hemma inte ha 2 brytare i samma grenuttag ens utan att det krånglar.. samma sak med både tellstick jag hade och RFXCom..
Du valde Raspberry som plattform.. jag har själv funderat lite på att det kanske hade varit bättre med något som inte har ett minneskort som media att köra ifrån.. de har ju en begränsad livslägnd.. kortare än en SSD eller vanlig HDD. Har du kört såna här saker så pass länge på raspberry så att man kan avfärda det som ett ickeproblem? Det är ju en del skrivade och läsande från kortet när den suger in data från som i mitt fall 8tempgivare 4 fuktgivare.. elmätare.. vattenmätare osv..
2 nyfikna frågor!
När du har kört 2st devicer brevid varandra som i lådan där, får du inte problem med att den bommar ofta då? Jag kan hemma inte ha 2 brytare i samma grenuttag ens utan att det krånglar.. samma sak med både tellstick jag hade och RFXCom..
Du valde Raspberry som plattform.. jag har själv funderat lite på att det kanske hade varit bättre med något som inte har ett minneskort som media att köra ifrån.. de har ju en begränsad livslägnd.. kortare än en SSD eller vanlig HDD. Har du kört såna här saker så pass länge på raspberry så att man kan avfärda det som ett ickeproblem? Det är ju en del skrivade och läsande från kortet när den suger in data från som i mitt fall 8tempgivare 4 fuktgivare.. elmätare.. vattenmätare osv..
- Electricguy
- Inlägg: 12307
- Blev medlem: 15 augusti 2007, 16:52:14
- Ort: Kälmä' typ..
Re: Hemautomation V2
Flashminne är en jättebra sak om man utgår från dess egenskaper. Vilket innebär att man undviker att genomföra upprepade skrivoperationer. Under unix bör man t.ex slå av uppdatering av "atime" i filsystemet. Men bäst är om man kan skrivskydda filsystemet som ligger på flashminne och använda disk i RAM för temporära filer. Loggning sparas tillfälligt i ett batteribackat RAM och skrivs sedan till flash så fort ett helt block har fyllts. Man kan t.om ordna en rå-partition där man kan ordna så att block för block fylls utan ett filsystem som försöker att uppdatera en massa metadata.
En annan fördel som kan uppnås med lite optimering av detta slag är att känsligheten för abrupt avslut blir mindre då filsystemet inte hamnar i odefinierat läge och sekvensiell skrivning kan ordnas som en logg.
En annan fördel som kan uppnås med lite optimering av detta slag är att känsligheten för abrupt avslut blir mindre då filsystemet inte hamnar i odefinierat läge och sekvensiell skrivning kan ordnas som en logg.
Re: Hemautomation V2
G-man: Jag har inte haft några problem med att de inte reagerar på kommandon men däremot en annan konstig sak.. För några dagar sedan började timern slås av när jag trycker på knappen för att slå av den andra strömbrytaren.. Detta är ju rätt lustigt med tanke på att jag inte alls har haft strömmen bruten eller tryckt på några inlärningsknappar. Tycker mig ha upplevt detta tidigare också på de lösa uttagen men avfärdade det med att jag måste ha glömt att jag hade en gammal kod inlagd i dem.
Vad gäller SD kortets livslängd vet jag faktiskt inte riktigt.. Jag funderade på detta rätt mycket förra gången jag gjorde min hemautomation eftersom jag då loggade temperatur direkt till minneskortet. Denna gången tänkte jag ladda upp det till en databas på mitt webhotell istället. På så sätt slipper jag upprepade skrivningar till minneskortet och jag slipper även köra Raspberryn som server. Förra gången hade jag en del problem med dynIP. Jag kollade runt på internet en del och trots hur många det är som har sina Raspberries ståendes på under långa perioder så hittade jag inte ett enda fall där någon faktiskt kunde bekräfta att minneskortet var slut, bara mycket spekulerande i att det skulle kunna hända. Men visst, där är väll inte fel att undersöka det som qx5 skriver. En annan metod om man inte är väldigt rädd om mätdatan skulle väl kunna vara att samla den i arbetsminnet tills man har kommit upp i storleken av en sektor och först då skriva allt till minneskortet. Tidigare har xxargs här på forumet skrivit:
Vad gäller SD kortets livslängd vet jag faktiskt inte riktigt.. Jag funderade på detta rätt mycket förra gången jag gjorde min hemautomation eftersom jag då loggade temperatur direkt till minneskortet. Denna gången tänkte jag ladda upp det till en databas på mitt webhotell istället. På så sätt slipper jag upprepade skrivningar till minneskortet och jag slipper även köra Raspberryn som server. Förra gången hade jag en del problem med dynIP. Jag kollade runt på internet en del och trots hur många det är som har sina Raspberries ståendes på under långa perioder så hittade jag inte ett enda fall där någon faktiskt kunde bekräfta att minneskortet var slut, bara mycket spekulerande i att det skulle kunna hända. Men visst, där är väll inte fel att undersöka det som qx5 skriver. En annan metod om man inte är väldigt rädd om mätdatan skulle väl kunna vara att samla den i arbetsminnet tills man har kommit upp i storleken av en sektor och först då skriva allt till minneskortet. Tidigare har xxargs här på forumet skrivit:
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)...
Re: Hemautomation V2
Jag kör domoticz på en raspberry och har haft problem vid ett par tillfällen med korrupt minneskort. Det har typisk kommit när man satt i eller tagit ur något ur USB-porten.
Jag planerar att NFS-mounta /var och katalogen där domoticz inkl databas huserar för att slippa problemen.
Jag planerar att NFS-mounta /var och katalogen där domoticz inkl databas huserar för att slippa problemen.
Re: Hemautomation V2
Har jobbat lite med mjukvaran under tiden som jag väntar på ordern. Nu har jag en fungerande tvåvägs kommunikation mellan dator och obegränsat antal (ja, praktiskt sett i min tillämpning) klienter (dvs smartphone eller surfplatta). Använder mig av sockets i Java. Finns demonstration och förklaring av mjukvaran på youtube.
https://youtu.be/m_gnn8ENSNM
https://youtu.be/m_gnn8ENSNM
Re: Hemautomation V2
Du gör alltså utveckligen *på* RPi'n framför TVn? Låter lite omständigt.
Re: Hemautomation V2
Kopplade bara in den till TV'n nu för att installera operativsystem och testa Java stödet. Väntar på USB WiFI nätverkskort till den samt en touch display. Sen skriver jag ju mjukvaran på min arbetsdator och flyttar över när det är klart. Kommer sätta upp SSH och FTP-server på raspberryn.
Re: Hemautomation V2
Väntar fortfarande på komponenterna så jag började med GUI till servern. Jag trodde jag hade beställt en 7" skärm men det visade sig att jag tydligen beställde 5" versionen, så det blir ju lite mindre... Blir nog bra ändå. Den skall monteras på väggen bredvid soffan i alla fall, sen kommer jag ju styra allt via telefonen och PIR-sensorer också.
Tar galet mycket tid att designa det i Java så att det rescalar sig bra till olika upplösningar. Så här långt har jag kommit än i alla fall. Väderprognos på vänster sida. Där skall också in temperatur inne och ute från mina givare. Till höger är TV-tablå för gratiskanalerna. I bottnen är knappar för att välja belysningsläge. Tror jag kommer ha den med vit text såhär istället. Funderar dock på om röd text kanske är bekvämare när det är mörkt? Väderprognoserna finns som XML utgivna av Yahoo, så de är lätta att ladda ned och parse'a. Skrev bara ihop en enkel klass för att ladda ned ett dokument från webben:
Sen parse'ar jag det med DOM:
Använder regex för att identifiera fem typer av väder utifrån beskrivningstexten än så länge.
Sparas i hashmap i en monitor som GUI't kan komma åt.
TV programmen var lite jobbigare för det verkar inte finnas något API för svenska kanaler. Men det gick snabbt att slänga ihop en enkel crawler som hämtar informationen från tv.nu
Tar galet mycket tid att designa det i Java så att det rescalar sig bra till olika upplösningar. Så här långt har jag kommit än i alla fall. Väderprognos på vänster sida. Där skall också in temperatur inne och ute från mina givare. Till höger är TV-tablå för gratiskanalerna. I bottnen är knappar för att välja belysningsläge. Tror jag kommer ha den med vit text såhär istället. Funderar dock på om röd text kanske är bekvämare när det är mörkt? Väderprognoserna finns som XML utgivna av Yahoo, så de är lätta att ladda ned och parse'a. Skrev bara ihop en enkel klass för att ladda ned ett dokument från webben:
Kod: Markera allt
public class WebDownloader {
String url;
public WebDownloader(String url) {
this.url = url;
}
public String getSource() {
try {
URL webPageURL = new URL(url);
URLConnection connection = webPageURL.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String line;
StringBuilder source = new StringBuilder();
while ((line = reader.readLine()) != null)
source.append(line);
reader.close();
return source.toString();
} catch (MalformedURLException e) {
System.out.println("Error: Malformed URL for source download");
} catch (IOException e) {
System.out.println("Error: IO Exception at source download");
}
return "";
}
}
Kod: Markera allt
public class DownloadWeather implements Runnable{
private static final String WEATHER_URL = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22lund%2C%20skane%2C%20se%22)%20and%20u='c'&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys";
private WeatherMonitor mon = new WeatherMonitor();
@Override
public void run() {
WebDownloader downloader = new WebDownloader(WEATHER_URL);
while (mon.isUpdating()) {
String source = downloader.getSource();
extractWeather(source);
try {
Thread.sleep(600000); // 10 minute
} catch (InterruptedException e) {
}
}
}
public WeatherMonitor getMonitor(){
return mon;
}
private void extractWeather (String source) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
StringBuilder xmlBuilder = new StringBuilder();
xmlBuilder.append(source);
ByteArrayInputStream stream = new ByteArrayInputStream(
xmlBuilder.toString().getBytes("UTF-8")
);
Document document = builder.parse(stream);
NodeList dayReports = document.getElementsByTagName("yweather:forecast");
for (int i = 0; i < dayReports.getLength(); i++){
Node n = dayReports.item(i);
DateFormat df = new SimpleDateFormat("dd MMM yyyy");
Date date = df.parse(((Element)n).getAttribute("date"));
mon.addReport(new WeatherReport(date,
Integer.parseInt(((Element) n).getAttribute("high")),
Integer.parseInt(((Element)n).getAttribute("low")),
((Element)n).getAttribute("text")
));
}
} catch (ParserConfigurationException e) {
System.out.println("Error: Parser configuration");
} catch (UnsupportedEncodingException e) {
System.out.println("Error: Unsupported encoding");
} catch (SAXException e) {
System.out.println("Error: SAX");
} catch (IOException e) {
System.out.println("Error: IO Exception DOM");
} catch (ParseException e) {
System.out.println("Error: date parsing");
}
}
}
Kod: Markera allt
// Class for storing a single days weather report
public class WeatherReport {
public Date date;
public int high, low, type;
public String text;
public WeatherReport(Date date, int high, int low, String text) {
this.date = date;
this.high = high;
this.low = low;
this.text = text;
setType();
}
// Extract the type of weather from the text
private void setType(){
if (text.toLowerCase().contains("snow"))
type = WeatherMonitor.SNOW;
else if (text.toLowerCase().contains("rain") || text.toLowerCase().contains("showers"))
type = WeatherMonitor.RAIN;
else if (text.toLowerCase().contains("partly cloudy"))
type = WeatherMonitor.PARTLY_CLOUDY;
else if (text.toLowerCase().contains("cloudy"))
type = WeatherMonitor.CLOUDY;
else if (text.toLowerCase().contains("sunny"))
type = WeatherMonitor.SUNNY;
else
type = -1; // Unknown type, use raw text instead of picture
}
// Write to string
public String toString(){
return date.toString() + ": " +
high + "'C/" +
low + "'C " +
text + ", " +
type + "\n";
}
// Clone
public WeatherReport clone(){
return new WeatherReport(date,high,low,text);
}
}
Kod: Markera allt
package Weather;
import java.util.*;
public class WeatherMonitor {
private Map<String, WeatherReport> reports = new HashMap<>();
private boolean update = true;
// Weather states
public static final int SNOW = 0;
public static final int RAIN = 1;
public static final int PARTLY_CLOUDY = 2;
public static final int CLOUDY = 3;
public static final int SUNNY = 4;
public synchronized void addReport(WeatherReport report){
reports.put(report.date.toString(), report);
removeOldReports();
}
public synchronized WeatherReport getReportDaysFromNow(int days){
Date day = new Date();
day.setTime(day.getTime() + (long)86400000*days);
String sDate = startOfDay(day).toString();
if (reports.get(sDate) != null)
return reports.get(sDate).clone();
return null;
}
public synchronized String toString(){
String s = "";
for (WeatherReport report : reports.values()){
s += report.toString() + "\n";
}
return s;
}
public synchronized void stop(){
update = false;
}
public synchronized boolean isUpdating(){
return update;
}
private void removeOldReports(){
Date startOfToday = startOfToday();
Iterator i = reports.entrySet().iterator();
while (i.hasNext()){
if (((Map.Entry<String, WeatherReport>)i.next()).getValue().date.getTime() < startOfToday.getTime())
i.remove();
}
}
private Date startOfToday(){
return startOfDay(new Date());
}
private Date startOfDay(Date date){
Calendar startOfDay = Calendar.getInstance();
startOfDay.setTime(date);
startOfDay.set(Calendar.HOUR_OF_DAY, 0);
startOfDay.set(Calendar.MINUTE, 0);
startOfDay.set(Calendar.SECOND, 0);
startOfDay.set(Calendar.MILLISECOND, 0);
return startOfDay.getTime();
}
}
Kod: Markera allt
public class TvGuideDownloader implements Runnable{
private static final String URL = "http://www.tv.nu/";
ArrayList<String> channels = new ArrayList<>();
TvGuideMonitor mon = new TvGuideMonitor();
public TvGuideDownloader(String [] channels) {
ArrayList<String> ch = new ArrayList<String>(Arrays.asList(channels));
ch.forEach((c)->this.channels.add(c.toLowerCase()));
}
public TvGuideMonitor getMonitor(){
return mon;
}
@Override
public void run() {
WebDownloader downloader = new WebDownloader(URL);
while (true) {
// Download source from page
String source = downloader.getSource();
// Split by channels
HashMap<String, String> channelData = splitChannels(source);
// Extract program info
ArrayList<TvProgram> programs = extractPrograms(channelData);
// Filter
programs.removeIf(p -> !channels.contains(p.getChannel().toLowerCase()));
programs.removeIf(p -> p.getTime().getTime() < (new Date()).getTime());
// Put in monitor
mon.setList(programs);
// Sleep
try {
Thread.sleep(60000); // 1 minute
} catch (InterruptedException e) {
}
}
}
private HashMap<String,String> splitChannels(String source) {
String regexp = "zeta color-gentle\\\">";
String [] s = source.split(regexp);
HashMap<String,String> channels = new HashMap<>();
for (int i = 0; i < s.length; i ++)
if (i != 0){
String [] channelData = s[i].split("</span>",2);
channels.put(channelData[0], channelData[1]);
}
return channels;
}
private ArrayList<TvProgram> extractPrograms(HashMap<String,String> channelData){
ArrayList<TvProgram> programs = new ArrayList<>();
String splitPoint = "data-id";
Pattern rProgramTitle = Pattern.compile("(?<=data-title=\")(.*)(?=\")");
Pattern rProgramTime = Pattern.compile("(?<=data-start-time-unix=\")(.*)(?=\")");
for (Map.Entry<String,String> entry : channelData.entrySet()){
String [] ps = entry.getValue().split(splitPoint);
for (String data : ps){
String title = "";
String time = "";
Matcher mTitle = rProgramTitle.matcher(data);
if (mTitle.find())
title = replaceHtmlCodes(mTitle.group().split("\"")[0]);
Matcher mTime = rProgramTime.matcher(data);
if (mTime.find())
time = mTime.group().split("\"")[0];
if (time.length() > 0 && title.length() > 0)
programs.add(new TvProgram(entry.getKey(), title, new Date(Long.parseLong(time) * 1000)));
}
}
return programs;
}
private String replaceHtmlCodes(String text){
String [] symbol = {" ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/"};
for (int i = 32; i <= 47; i ++){
text = text.replaceAll("\\&#" + Integer.toString(i) + ";", symbol[i-32]);
text = text.replaceAll("\\�" + Integer.toString(i) + ";", symbol[i-32]);
}
return text;
}
}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Hemautomation V2
Fick min leverans idag. Tog hela kvällen att få igång touchskärmen. Inga instruktioner, tillverkare eller nått. När jag väl lyckades googla fram drivrutiner till den så kraschade datorn varenda gång jag hade installerat dem och jag blev tvungen att installera om en ny avbild av Raspbian för att få igång den. Efter väldigt mycket trixande visade det sig att root partitionen blev full direkt så jag var tvungen att göra partitionen större.
Nu är den igång och kör serverprogrammet i alla fall! Går faktiskt väldigt bra att läsa texten på lite avstånd, trodde att det skulle bli väldans smått på denna skärmen men det känns rätt lagom faktiskt. Notera att jag kör med WiFi dongel trots att den står mindre än 2dm från routern. Man tager vad man haver.
Nu är den igång och kör serverprogrammet i alla fall! Går faktiskt väldigt bra att läsa texten på lite avstånd, trodde att det skulle bli väldans smått på denna skärmen men det känns rätt lagom faktiskt. Notera att jag kör med WiFi dongel trots att den står mindre än 2dm från routern. Man tager vad man haver.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Hemautomation V2
http://tvsajten.com/tv skall ha XML filer för svenska kanaler.
Om det är trögt att skriva i Java så kanske något annat datorspråk för att uttrycka det du vill göra vore bättre?
Om det är trögt att skriva i Java så kanske något annat datorspråk för att uttrycka det du vill göra vore bättre?
Re: Hemautomation V2
Har varit väldigt fullt upp på sista tiden men idag fick jag ett par timmar över. Raspberryn skall styra min belysning med 433Mhz via nexa-mottagarna. Finns ju en hel del dokumentation på internet om protokollet men jag ville veta ID-numret på min sändare ändå så jag bestämde mig för att att göra reverse engineering på min sändare. Sändaren är gjuten/limmad ihop och jag kände inte för att plocka isär den så jag kopplade bara upp oscilloskopet till sändarens batteri.
Som ni ser så stämmer alla fyra avkodade sändningar överens med varandra, typiskt bra tecken.
Jag tolkar (i motsats till forumets wiki) en 01 som etta och 10 som nolla. Detta gör att min information kan tolkas som följande:
Nu skall det bara hackas ihop ett program till PIC eller Arduino som kan sända och ta emot enligt protokollet. Det skall då såklart kompletteras med dimningsfunktionen.
Och jodå, mycket riktigt kunde man se att spänningen sjönk när den sänder. Här är vad oscilloskopet visade.
Ser inte så givande ut men jag öppnade mätningarna med Matlab och skrev ihop ett skript som först binariserar mätningarna, sen räknar det ut de vanligt förekommande tiderna för hög och låg signal och läser tillsist ut rådatan i sändningen. Här har skriptet plottat den binära datan och pilar som visar vilket håll den har avkodat informationen.
Utdatan från skriptet blev följande:
Kod: Markera allt
High signal delay:
278 µS,
Low signal delay:
300 µS,
1343 µS,
---------------100110101010101010010110011010100101101001101010010
010100101101010100110101010101010010110011010100101101001101010010
010100101101010100110101010101010010110011010100101101001101010010
010100101101------------------------------------------------------
Jag tolkar (i motsats till forumets wiki) en 01 som etta och 10 som nolla. Detta gör att min information kan tolkas som följande:
Kod: Markera allt
START UNIKT ID Grupp Av/på Kanal Knapp Stopp
0 1010010110101010011010101010101001011001101010010110 10 01 1010 1001 0
Grupp: 10->0 (Ej gruppkommando)
Av/På: 01-> 1 (på)
Kanal: 1010-> 00
Knapp 1001 -> 01 (knapp 2)
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Hemautomation V2
Om någon är nyfiken på matlab-skriptet:
Kod: Markera allt
sec_per_div = 25000; % µS
plotOscData_1CH
time_per_sample = sec_per_div * 10 / size(CH1,1);
%% BINARIZE THE SIGNAL
maxVal = max(CH1);
minVal = min(CH1);
midVal = (maxVal + minVal)/2;
n = size(CH1, 1);
CH1_bin = zeros(n,1);
for i = 1:n
CH1_bin(i) = (CH1(i) > midVal);
end
plot(1:n, CH1_bin);
set(gca,'units','pixels')
set(gcf,'units','pixels')
axesPos = get(gca,'position');
figurePos = get(gcf,'position');
set(gcf,'position',[figurePos(1) figurePos(2) axesPos(3)+50 axesPos(4)+50])
set(gca,'units','normalized','position',[0 0 1 1])
%% FIND ON AND OFF DELAYS
on_delay = [];
off_delay = [];
tRise = 1;
tFall = 1;
lastVal = CH1_bin(1);
for i = 1:n
if CH1_bin(i) ~= lastVal
if CH1_bin(i) > 0.5
off_delay_ = i - tFall;
off_delay = [off_delay ; off_delay_];
tRise = i;
else
on_delay_ = i - tRise;
on_delay = [on_delay ; on_delay_];
tFall = i;
end
end
lastVal = CH1_bin(i);
end
% Make a histogram
on_hist_offset = min(on_delay) - 1;
off_hist_offset = min(off_delay) - 1;
on_hist = zeros(max(on_delay)-on_hist_offset,1);
off_hist = zeros(max(off_delay)-off_hist_offset,1);
on_d_n = size(on_delay,1);
off_d_n = size(off_delay,1);
for i = 1:(max(on_d_n, off_d_n))
if i <= on_d_n
on_hist(on_delay(i) - on_hist_offset) = on_hist(on_delay(i) - on_hist_offset) + 1;
end
if i <= off_d_n
off_hist(off_delay(i) - off_hist_offset) = off_hist(off_delay(i) - off_hist_offset) + 1;
end
end
% Find the common on and off delays
common_on_delays = find(on_hist > on_d_n / 10) + on_hist_offset;
common_off_delays = find(off_hist > off_d_n / 10) + off_hist_offset;
% If two delays are very close, replace with the weighted average
i = 1;
while i < size(common_off_delays,1)
indexes_close = find(abs(common_off_delays(i)-common_off_delays) < 3);
if size(indexes_close,1) > 1
% Calc the product sum of the values and the times they appear
hist_indexes = common_off_delays(indexes_close)-off_hist_offset;
common_off_delays(i) = sum(common_off_delays(indexes_close).*off_hist(hist_indexes));
% Divide by total times they appear
common_off_delays(i) = common_off_delays(i) / sum(off_hist(hist_indexes));
% Remove duplicated
common_off_delays(indexes_close(indexes_close ~= i)) = [];
end
i = i + 1;
end
i = 1;
while i < size(common_on_delays,1)
indexes_close = find(abs(common_on_delays(i)-common_on_delays) < 3);
if size(indexes_close,1) > 1
% Calc the product sum of the values and the times they appear
hist_indexes = common_on_delays(indexes_close)-on_hist_offset;
common_on_delays(i) = sum(common_on_delays(indexes_close).*on_hist(hist_indexes));
% Divide by total times they appear
common_on_delays(i) = common_on_delays(i) / sum(on_hist(hist_indexes));
% Remove duplicated
common_on_delays(indexes_close(indexes_close ~= i)) = [];
end
i = i + 1;
end
disp('High signal delay: ')
for i = 1:size(common_on_delays,1)
disp(sprintf('%d µS, ', round(common_on_delays(i) * time_per_sample)))
end
disp('Low signal delay:')
for i = 1:size(common_off_delays,1)
disp(sprintf('%d µS, ', round(common_off_delays(i) * time_per_sample)))
end
%% DECODE THE SIGNAL
if size(common_on_delays,1) == 1 && size(common_off_delays,1) == 2
disp('Partial data:');
data = [];
% Find the start and end of each transmission
pause = [;];
potential_start_of_pause = 1;
i = 1;
lastVal = 0;
for i = 2:n
if CH1_bin(i) < 0.5 && lastVal == 1
potential_start_of_pause = i;
end
if (CH1_bin(i) > 0.5 && lastVal == 0) || i == n
if i - potential_start_of_pause > max(common_off_delays) * 5
pause = [pause [potential_start_of_pause;i]];
end
end
lastVal = CH1_bin(i);
i = i + 1;
end
% Start decoding in backward direction
if (size(pause,2) > 0 && pause(1,1) > 1)
% Plot direction of parsing arrow
arrowX = [pause(1,1)/n 0];
annotation('textarrow', arrowX, [0.5 0.5]);
% Decode..
tRise = pause(1,1) + common_off_delays(2); % Always end with zero
raw_data_back = '';
lastVal = 0;
bit_ok = 1;
i = pause(1,1);
while size(raw_data_back,2) < 66
if i > 0
if CH1_bin(i) ~= lastVal
if CH1_bin(i) > 0.5
offTime = tRise - i;
if bit_ok == 1
if find(abs(common_off_delays - offTime) == min(abs(common_off_delays - offTime))) == 1
raw_data_back = strcat('1', raw_data_back);
else
raw_data_back = strcat('0', raw_data_back);
end
end
tFall = i;
else
onTime = tFall - i;
if (abs(onTime - mean(common_on_delays)) < onTime / 2)
bit_ok = 1;
end
tRise = i;
end
end
lastVal = CH1_bin(i);
else
raw_data_back = strcat('-', raw_data_back);
end
i = i - 1;
end
disp(raw_data_back)
data = [data ; raw_data_back];
end
% Start decoding in forward direction
if size(pause,2) > 0 && pause(2,1)~=n
for signal = 1:size(pause,2)
tStart = pause(2,signal);
% Plot direction of parsing arrow
if size(pause,2) > signal
arrowX = [tStart/n pause(1,signal+1)/n];
else
arrowX = [tStart/n 1];
end
annotation('textarrow', arrowX, [0.5 0.5]);
% Decode...
bit_ok = 0;
raw_data = '';
lastVal = 0;
tFall = i;
tRise = i;
i = tStart;
while size(raw_data,2) < 66
if i <= n
if CH1_bin(i) ~= lastVal
if CH1_bin(i) > 0.5
offTime = i - tFall;
if offTime ~= 0
if bit_ok == 1
if find(abs(common_off_delays - offTime) == min(abs(common_off_delays - offTime))) == 1
raw_data = strcat(raw_data, '1');
else
raw_data = strcat(raw_data, '0');
end
end
end
tRise = i;
else
onTime = i - tRise;
if (abs(onTime - mean(common_on_delays)) < onTime / 2)
bit_ok = 1;
end
tFall = i;
end
end
lastVal = CH1_bin(i);
else
raw_data = strcat(raw_data, '-');
end
i = i + 1;
end
disp(raw_data)
data = [data ; raw_data];
end
end
%% Check if all data is consistent
ok = 1;
for i = 1:size(data,2)
bits = [];
for j = 1:size(data,1)
if data(j,i) ~= '-'
bits = [bits int32(data(j,i)-'0')];
end
end
if range(bits) ~= 0
ok = 0;
end
end
if ok == 1
complete_data = '';
for i = 1:size(data,1)
complete_data(find(data(i,:) ~= '-')) = data(i,(find(data(i,:) ~= '-')));
end
disp('Complete data:');
disp(complete_data);
% Parse the data
if (isempty(find(complete_data == '-')))
split_on = [1 27 28 29 31 33];
nbr_spaces = 0;
parsed_data = [complete_data(1)];
for i = 2:2:size(complete_data,2)-1
% Add spaces
if any(abs(split_on-(size(parsed_data,2)-nbr_spaces))<0.5)
parsed_data = [parsed_data ' '];
nbr_spaces = nbr_spaces + 4;
end
%% Parse a bit
if complete_data(i) == '0' && complete_data(i+1) == '1'
parsed_data = [parsed_data '1'];
else
parsed_data = [parsed_data '0'];
end
end
parsed_data = [parsed_data ' ' complete_data(end)];
disp('Parsed data:');
disp(parsed_data);
parsed_data = strsplit(parsed_data);
fprintf('ID: %d\nGroup: %d\nValue: %d\nChannel: %d\nButton: %d\n\n', bin2dec(parsed_data(2)), bin2dec(parsed_data(3)), bin2dec(parsed_data(4)), bin2dec(parsed_data(5)), bin2dec(parsed_data(6))+1)
end
else
disp('Data is inconsistent');
end
else
displ('To many common on or off times, fine tune parameters to get 1 or 2 on times and 2 off times')
end
Senast redigerad av squiz3r 13 mars 2016, 15:24:46, redigerad totalt 1 gång.