Category Archives: Tech

Az Apple dongle hisztiről

Preface: Soha nem szoktam ilyen "vallási" témáról írni, a jelenlegi poszt csak azért születik, mert még sehol nem olvastam a sajátommal egyező véleményt.

A múlt héten az Apple frissítette a MacBook Pro palettát, melyen a legkisebb, 13"-os gépük 2 db, míg a többi 4 db USB C csatlakozót kapott (a 3.5"-os Jack lyuk mellett). Az USB C új szabvány, kevés még az USB C portra direktben rádugható eszköz - a szabvány váltás miatt a korábbi kütyükhöz mind adapterre van szükség, ha azokat az új gépünkkel használnák. Lassan annyi dongle kapható Apple termékekhez, hogy azokkal fontot lehet rajzolni:

apple-dongle-font
image source: @andy23 Twitter

Én jelenleg egy mid-2012-es, első generációs minimal config MacBook Pro-t használok, amin a MagSafe tápcsatlakozón és a 3.5"-es jack lyukon túl 2 db Thunderbolt, 2 db USB 3, 1 db HDMI és egy normál SD kártya bemenet található. Ennek ellenére minden nap az alábbi szettel megyek terepre:

my-edc-apple-dongles

A fenti kép kicsit gonosz, mert a két jobb oldali dongle nélkül is túlélek melóban, azok csak azért vannak velem, mert egy tasakban tartom az összes donglét plusz minden drótot és ezek egyszerre jönnek velem, akár melóba megyek, akár víz alá.

A fotón balról jobbra az alábbi játékszerek láthatóak:

  • analog VGA - DisplayPort: ez akkor kell, ha olyan meeting roomban akarsz prezentálni, ahol a projektoron csak analog VGA van, illetve a mennyezetről csak azt vezeti ki drót a gépedig (amerre én járok, ott az esetek >70%-a ilyen)
  • DVI - DisplayPort: arra az esetre, ha (csak) digitális videojelet fogadó DVI port lenne a projektoron, vagy esetleg ilyet tudó monitor van a pool asztalon, mert ugye ha van digitális video in, akkor mégsem vagyunk állatok, hogy analógot használjunk
  • USB - Ethernet: ha nincs WiFi, vagy van, de az enterprise IT nem ad hozzáférést (bizony, ilyen simán létezik). Ez csak 10/100 mbps, van belőle gigabites Thunderbolt verzió is, de az a containerben hajózik éppen.
  • USB + Lightning - Lightning: iPadhez, ha tápot is adnál neki meg fotót/videót is töltenél fel rá egyszerre (búvározós szituációban nagyon hasznos tud lenni).
  • USB - Lightning: ez ugyanarra jó, mint az előző - USB connectiont ad iOS eszközhöz. A végén lógó kék infrás DiveMate Fusion IR nevű bigyó egy gateway az iOS-es DiveMate app és az IR protokollt beszélő búvárcomputerek közé.

Szóval nálam ezekből 3 mindenképpen ott van. Ha most gépet váltanék, mind a három dongle helyett újra lenne szükség, plusz nagy eséllyel beszereznék:

  • egy HDMI - USB C donglét, hogy ha csak HDMI van terepen, akkor azt tudjam használni
  • egy USB - USB C donglét, hogy amíg ki nem kopik nálam minden USB, addig tudjam őket használni az új géppel
  • egy Thunderbolt 1/2 - USB C donglét vagy jobb esetben egy rövid Thunderbolt 1/2 - USB C kábelt, hogy a külső Seagate GoFlex dokkomat se kelljen kidobni

Ha 50 USD / dongle átlagárral számolunk, akkor ez 300 USD plusz költséget jelent.

Nekem nem azzal van problémám, hogy egy szabvány kikopik és az Apple veszi a bátorságot, hogy kidobja. Sokkal inkább az zavar, hogy a leglojálisabb, Pro gépeket használó vásárlóival sem kegyes annyira, hogy az új szabványra való első teljes átálláskor mellékelne egy váltást megkönnyítő dongle packot.

Számoljunk egy kicsit. A cég egy év alatt cirka 2.5 millió notebookot ad el és mondjuk vegyünk másfél éves gépfrissítési ciklust alapul. Tegyük fel, hogy a Pro usernek egyféle régi szabványú video out és egy obsolete USB port hiányzik veszettül.
Ha úgy állnának oda a pódiumra, hogy az új szabvány bevezetésekor ott van az új 1st gen gépek dobozában a 2 extra dongle (ami jelen kalkulációban 2.5 * 1.5 * 2 = 7.5 millió drótot jelent), akkor akár az is lehet, hogy kevésbé lenne keserű a szoftver fejlesztésből élő Apple notebook userek szájíze. Akár akkor is, ha 2 dongle árával megemelnék a termékek árát, annak ellenére, hogy az évi 200+ milliárd USD bevétel lehet, hogy elbírná a ~4 millió Pro user felé gyakorolt gesztust.

PS.: ez a poszt pusztán arról szólt, hogy nem szeretem, hogy a világ legtöbb tech pénzét termelő vállalata nem empatikus a lojális Pro vevőivel szemben. Ezért aztán arról commentben is kár beszélnünk, hogy:

  • túl kevés az új gépeken a port, úgyhogy még USB C elosztó / docking station / bármi más is kéne
  • nem tudom hozzádugni az új iPhone 7-et sem az új MacBook Pro-khoz
  • miért nem fért el legalább egy microSD slot a házban (holott ezért én is ölnék)
  • miért megy a vékonyítás hiszti ahelyett, hogy még akkut kapnánk
  • et cetera

Home automation: építsünk detektívet!

Preface

2012 márciusában lecseréltük a hagyományos kazánt kondenzációsra és ha már lúd legyen kövér alapon telepítettünk mellé 5 m² váklumcsöves napkollektort is a hozzá való köcölékekkel (hőtároló puffer, hőcserélő, frissvíz modul, vezérlés, etc.) egyetemben. A választás némi kutatás után a Vaillant termékére esett.
2016 augusztus közepén egy meleg nyári napon forró etilénglikol szaga áradt a kazánházból. Elég volt egy pillantás a szabályzóra, hogy észrevegyük: a kinti hőség ellenére a kollektorokból egy csepp meleget sem szed le a rendszer. Ráadásul ekkor tűnt csak fel, hogy a baj már 2016 júniusában bekövetkezett, csak akkor nem vettük észre.

Melegcsináló HOWTO

Mielőtt a lényegre térnék, muszáj dióhéjban ideMórickázom, hogy működik a fűtésünk:

r9-heating

Gondolom rájössz magadtól, de azért: a rajzon a zöld az áramlási irányokat jelöli, a piros a meleg közeget, a kék a hideget.

Az 1. napkollektoroktól a 2. szivattyú behúzza a hőszállító etilén-glikolt a 3. hőcserélőbe, aki a glikol melegét beletolja a 4. puffertartályba. Ha a háznak melegre van szüksége, akkor az 5. hőcserélővel a 6. szivattyú csinál a csapvízből meleget, vagy a 7. szivattyú a fűtési körökben levő folyadékokra melegít rá egy kicsit. Az egészhez persze csatlakozik még egy kazán is, de azzal most semmi dolgunk, úgyhogy ezért lehagytam a Mórickáról.

A solar körön a 3. hőcserélő után van egy nyomásmérővel ellátott biztonsági szelep, amiből egy hosszú rézcső megy be egy nyitott puffertartályba. Erre azért van szükség, hogy ha valami hiba folytán a nyomás alatt levő solar kör belső nyomása elérné az 5 bar-t, akkor ez a biztonsági szelep egyszerűen leengedi a glikolt ahelyett, hogy hagyná felrobbanni a csöveket.

Nyomozás v1.0

Az augusztus közepén detektált problémát a szerelő úgy korrigálta, hogy újratöltötte a glikolt a nyomás alatt üzemelő rendszerben. A szakember arra tippelt, hogy valószínűleg hosszabb ideig nem voltunk otthon, így nem volt hőelvétel a pufferből és a termelődött meleget a vezérlés már nem tudta hova rakni, így ennek megfelelően a túlmelegedő glikol nyomása elérte az 5 bar-t, a biztonsági szelep leeresztett és onnantól nem volt ami lehozza a meleget a tetőről.

Ezt el is fogadtam, viszont nagyon nem hagyott nyugodni, hogy a problémáról a rendszer semmiféle módon nem tájékoztat. A dolgot úgy veszed észre, hogy a kinti hőség ellenére azt látod a vezérlő kijelzőin, hogy aznap semmi hőt nem termelt a solar kör, illetve a hosszabb időtartamú kiesés is megfigyelhető egy buta havi bontású oszlopdiagrammon.

Nekem ez kevés. Én tudni akarom, hogy pontosan mi történik a solar körben, illetve elektronikusan akarom detektálni azt, amikor ismét előáll a probléma és erről push notificationt akarok küldeni a fiúknak, akik majd riasztják a szervizest. Persze az igazi az lenne, ha a solar kör nem hibázna, ám mint pár óra telefonálgatás után megtudtam, erre a nyomás alatt levő solar rendszerek nem alkalmasak, csak a mostanában gyártott, önmagukat leereszteni és újratölteni képes kollektoros installációk. A sajátom természetesen ezekkel nem kompatibilis.

Azt találtam ki, hogy a glikolt szállító csőre hőcserélő bemeneténél és a biztonsági szelepnél is teszek fel egy-egy PT-1000-es hőmérőt, 10 percenként mérek velük egyet és a mért értékeket naplózom egy sql táblába. Ezen felül azt gondoltam, hogy talán jó indikátor lesz a meghibásodásra, ha a bizontsági szelepnél mért hőmérséklet elér egy határértéket (70 ℃-ra saccoltam), aminek hatására már küldhetem is a figyelmeztetést a gyerekeknek.

Felszereltem a hőmérőket, beállítottam a homeaut serverben a naplózást, megcsináltam a vizualizáló interfészt, körbeteszteltem szépen mindent és úgy gondoltam kész vagyok, de persze tévedtem.

A következő meghibásodás kb. 2 héttel az előző hiba kijavítása után következett be. Sajnos a biztonsági szelep utáni hőmérséklet teszt nem bizonyult hatásosnak: a cső nem melegedett 45 ℃ fölé. Ennek ellenére a hőmérő naplózás nem bizonyult hiábavalónak - mindjárt meg is mutatom! A biztonsági szelepnél levő hőmérővel most nem foglalkozunk, elég tanulságos lesz a solar kör hőcserélőjének bemeneti hőmérséklete.

Az első grafikonon azt látod, amikor a rendszer normálisan működik két egymást követő, kb. egyformán meleg napon:
solar-temp-log-OK

Ezen pedig jól látszik, hogy a 2. napon 9:30 tájban pusztul meg ismét a rendszer:
solar-temp-log-FAILURE

Két egymást követő kb. egyforma napon a normál működést tanulmányozva nagyon jól látszik, hogy mi történik a rendszerben:

  • 6:10: az éjszaka után beindul a solar szivattyú. Az ezt követő 10 percben ~10 ℃-t esik a hőmérséklet, mivel az éjszaka során meghűlt a kollektorban levő glikol és a szivattyú épp ezt a hidegebb folyadékot hozza le a hőcserélőbe.
    A kollektor és a hőcserélő közti csőszakasz valamint a padlástér is vastagon szigetelt, ezért abban csak nagyon lassan hűl ki a hőszállító folyadék - ez láthatod az éjféltől kezdődő első szakaszon.
  • 7:20: felkel a nap, a kollektorok elkezdik termelni a meleget.
  • 15:00: a hőtermelés csúcsa, kb. ekkor süti optimális szögben a nap a kollektorokat. Innentől kezdve lassan csökken a glikol hőmérséklete, de még mindig van bőven hőmermelés.
  • 20:00: lemegy a nap, a hőmermelés megszűnik. A hőtároló pufferben már legalább 60 ℃ hőmérsékletű víz van, így az ennél hűvösebb glikolból a hőcserélő már nem vesz el meleget. A görbe simulása egyenletesebbé válik, ami azt is jelzi, hogy a szivattyú már nem keringtet, a csőben levő hőszállító folyadék magától hűl le lassan.

Ha ránézel a 2. ábrára, akkor arról a fentiek alapján a meghibásodás napján (=kék diagram) ugyanígy leolvasható a történet:

  • 9:00: A lassan hűlő glikolt 6:10 helyett 9:00-kor mozdítja meg a keringtető szivattyú. A hőcserélő visszahűlése jóval kevesebb ideig tart, mivel a kollektor ilyenkor már baromi meleg.
  • 9:30: a hőmérséklet ezerrel emelkedik.
  • 9:50: az utolsó mért meleg érték - a nyomás alatt levő csőrendszer itt éri el az 5 bar határértéket, a biztonsági szelep leereszti a glikolt. Innentől már csak a lassú kihűlés marad, mivel nincs hőszállító közeg.

A fentieket megmutattam a szerelőnek, aki a rendszert ismét átnézve arra jutott, hogy a hőcserélő szivattyúja adta meg magát. Én továbbra is azt látom a diagrammokon, hogy az eltelt 2 hétben a szivattyú minden nap 6:10-kor indul, kivéve a meghibásodás napját, amikor 9:00-kor mozdította meg először a folyadékot. Szerintem inkább a vezérléssel nem stimmel valami.

A második hiba után szeptember 5-én a csöveket trisóval átmosták, a hibásnak gondolt szivattyút kicserélték, majd 2 nappal ezután a következőt rajzolta nekem reggelire a log:

solar-temp-log-WARNING

A kék vonal megint azt mutatja, hogy a szivattyú egy órával később kapcsol. A vezérlésnek nincs internetkapcsolata, tehát nem tud az időjárásról, mindössze annyit ismer a környezetéből, hogy Magyarországra telepítették és hogy épp mennyi a pontos idő.

Nyomozás v2.0

A fentiek alapján azt feltételezem, hogy a rendszer hamarosan ismét megadja magát. A logok nekem már most is egyértelműek, viszont ettől lehetnének egy picit még precízebbek is, ezért a következő tuningot eszeltem ki:

  • A biztonsági szelepen levő hőmérő átkerül a hőcserélő kimeneti oldalára, így a két mért értékből jól látszik majd, hogy a puffer felvette-e a tetőről lehozott hőt.
  • A szivattyú tápellátására párhuzamosan rákötök egy 230 V AC-re kapcsoló relét, aminek a kapcsolt NO lábát odaadom egy digitális bemenetnek a homeaut buszon. Ezzel értesülni fogok arról, hogy mikor indult és mikor állt le a szivattyú.
  • Ha már tudom, hogy mikor megy a solar szivattyú, akkor elég lesz akkor megmérnem a két hőmérsékletet - illetve egész pontosan mondjuk 30 másodperccel a szivattyú indulása után, hogy biztosan a lehozott hőszállító folyadékot mérjem.

Amióta ern0vel összeraktuk a dataflow alapú homeaut servert, nincs az a probléma, aminek a megoldását ne lenne élvezetes implementálni homeaut oldalon egy kis dataflow script módosítással. Lényegében az egész terjengős posztot azért kellett végigrágnod, hogy meg tudjam mutatni neked, hogy csináltam!-)

A fizikai adatbuszról a fenti probléma megoldásához kétféle adatra van szükségünk: egy digitális bemenetére (amire a keringtető szivattyú tápjával vezérelt 230 V AC-s relét kötöm) és a PT-1000-es hőmérők által mért analóg értékekre. A digitális inputokat 100 msec-enként lekérdezem egyben, úgyhogy az már kész, viszont a házban levő 8 darab PT-1000-es hőmérőt csak 10 percenként kérdeztem le eddig, mert a többit bőven elég ilyen lépesközzel naplózni, a két solar hőmérő naplózását viszont a szivattyú bekapcsolásának kellene vezérelni mostantól. A dolog azért problémás, mert a 8 darab hőmérőből 4-et csak egyszerre tudok lekérdezni a Wago MODBUS interface-en. Szerencsére itt van a kezem alatt a dataflow nevű rágógumi, amit a végtelenségig lehet nyújtani - nézzük meg, hogy hogyan csinálom!

Dataflow gyorstalpaló

Ha tudod, mi az a dataflow, akkor menni fog az is, ami lejjebb következik - ha viszont nem, akkor ern0 barátom eldarálja neked elképesztő sebességgel 10 percben (amiből a második ~5 perc már csak a kérdésekre adott válasz):

Dataflow from Budapest New Tech Meetup on Vimeo.

ern0 közben feltöltötte youtube-ra a tavalyi hosszabb dataflow meetup videót is - hardcore rajongóknak kötelező ez is:

Megoldunk

Ezek után lássuk, hogy raktam mindezt össze:

log_df_visualized

Ha inkább a scriptet olvasnád, mint a vizualizált ábrát, az így néz ki (btw a fenti rajzot ern0 kódja generálja graphvizzel a lenti dataflow scriptből :)):

component Main {
	implementation {
		carpet log {

			// create pulsars
			p100ms: RTCPulsar
			p100ms.freq = 100000

			p1s: RTCPulsar
			p1s.freq = 1000000

			// create 10 min scheduler
			p100ms.out >> sched10min.clock
			sched10min: Scheduler
			sched10min.mask := "schedule={mi=0,10,20,30,40,50 se=0}"

			// feed Wago digital poll
			p100ms.out >> wdp.digipoll
			wdp: WagoPoll
			wdp.digibase = 0
			wdp.digipollsize = 96
			wdp.anabase = 0
			wdp.anapollsize = 4
			wdp.serout >> s1.in

			s1: Serial
			s1.device := "wago_ip:502"

			s1.out >> di4_1.serin
			di4_1: WagoDigiIn
			di4_1.base = 48

			// feed Wago analog poll
			p1s: RTCPulsar
			p1s.freq = 1000000
			p1s.out >> wap.anapoll

			wap: WagoPoll
			wap.anabase = 0
			wap.anapollsize = 4
			wap.serout >> s2.in

			// Wago bus
			s2: Serial
			s2.device := "wago_ip:502"

			// split Wago analog input msg
			s2.out >> ai1.serin
			ai1: WagoAnaIn
			ai1.base = 0
			ai1.size = 8 // 4 input, 2 byte/input

			// store temps in Value components
			ai1.out1 >> temp1.setvalue
			ai1.out2 >> temp2.setvalue
			ai1.out3 >> temp3.setvalue
			ai1.out4 >> temp4.setvalue

			temp1: Value
			temp2: Value
			temp3: Value
			temp4: Value

			// send measured temps to sql loggers from the first 3 thermometers
			sched10min.out >> temp1.in
			sched10min.out >> temp2.in
			sched10min.out >> temp3.in

			temp1.out >> sql1_1.in
			temp2.out >> sql1_2.in 
			temp3.out >> sql1_3.in
			temp4.out >> sql1_4.in

			// define sql loggers for all 4 thermometers
			sql1_1: Shell
			sql1_1.command := "./log_temp.py r9_nagyhaz_nappali"
			sql1_2: Shell
			sql1_2.command := "./log_temp.py r9_solar_test"
			sql1_3: Shell
			sql1_3.command := "./log_temp.py r9_utca"
			sql1_4: Shell
			sql1_4.command := "./log_temp.py r9_napkollektor"

			// di4_1.out1 = solar pump power state change
			di4_1.out1 >> change4_1.value
			change4_1: Change
			change4_1.last = 0
			change4_1.zero >> log_solar_pump.in = 0    // log pump OFF state
			change4_1.nonzero >> log_solar_pump.in = 1 // log pump ON state
			change4_1.nonzero >> d30s_4_1.in           // log temp with delay after pump switched on

			// log solar pump state
			log_solar_pump: Shell
			log_solar_pump.command := "./log_di.py r9_solar_pump"

			// log thermometer wiuth a 30 sec delay
			p100ms.out >> d30s_4_1.clock
			d30s_4_1: Delay
			d30s_4_1.delay = 300
			d30s_4_1.out >> temp4.in // log temp with 30s delay after pump has started
		}
	}
}

Elmagyarázom a rajzot - a legjobb, ha kinyitod teljes méretben :)

Start

Kezdetben azt csináltam, hogy egy 10 perces scheduler (=sched10min) lökdöste meg az analog inputokat pollozó wap komponenst és az abból kiálló ai1 analóg poll értelmező meghívott négy darab, sql insertet elvégző scriptet (sql1_1..sql1_4), akik megcsinálták a naplózást. Ezzel az a baj, hogy a 4. hőmérőt csak akkor akarom naplózni, amikor a szivattyú beindul, a többi meg maradhat 10 percenként.

Flow detection

Első körben detektálni kellett a szivattyú indulását. Ehhez csak a solar vezérlőből a szivattyúnak adott 230 V AC tápra kell párhuzamosan rákötni egy 230 V AC által kapcsolt relét, aminek a másik végébe jön a 24 V DC kimenetünk, akit a buszon a di4_1 modul out1 lábára kötünk.
Nekem akkor kell naplóznom a solar folyadék hőmérsékletét, ha a szivattyú megindul (egész pontosan kicsivel utána), így a di4_1.out1 láb 0-ról 1-re történő állapotváltozása kell, hogy kiváltsa a naplózást. Az állapotváltozás detektálására ott van a change4_1 komponensünk, aminek a zero illetve nonzero lábain csak akkor jelenik meg trigger, ha a bemenetén az előző inputhoz képest más adat jelenik meg.

Logging

Innentől már nincs nehéz dolgunk, csak be kell kötni a change4_1.nonzero kimenetet a d30s_4_1 30 másodpercre állított delay komponensbe, akinek az out kimenetével indíthatjuk a naplózást.

Analog poll

Az analóg input olvasásán is változtatni kellett. Egyrészt a 10 perces kérések helyett másodpercenként kérdezzük le a modult (ezért bökdösi a p1s 1 másodperces Pulsar komponens a wap analóg input poll generátort a korábbi sched10min 10 perces trigger helyett), másrészt az ai1 analóg input választ feldolgozó komponens lábait a közvetlen naplózás helyett a temp1..temp4 Value komponensekbe kötögettem. A temp1..temp4 value komponensek tárolják a mért értékeket, a kimenetük indítja meg a bennük levő érték naplózását, amit az sql1_1..sql1_4 Shell komponensek végeznek el. A temp1..temp4 komponensekből az első hármat a sched10min 10 perces időzítő triggereli, míg a negyediket (amiben a solar folyadék hőmérsékletét tároljuk) a di4_1.out1 komponens kimeneten megjelenő 0->1 érték változás indítja.

Extras

Ha már egyszer detektálom a szivattyú indulását (és leállását is, hiszen a change4_1 komponens mindkét állapotváltozást megadja), akkor ezt is simán lehet naplózni - erre való a change4_1 zero és nonzero lábaira kötött log_solar_pump komponens. Innentől a következő hibánál nincs vita, hogy mikor indította el a solar vezérlés a szivattyút.

Szummárium

Hétvégén megcsinálom a hardveres részt is, aztán még készül hozzá egy olyan diagram, ami a solar kör hőmérő által mért értékeket együtt mutatja a keringtető szivattyú állapotváltozásával és onnantól már kellőképpen felvegyverkezve várom a következő hibát.

Az autók és a kriptográfia

Ez jó száraz lesz, kép nélkül meg úgysem kezdesz neki, úgyhogy iderakom az előbb elkészült low&slow oldalast, az szaftos is meg szép is - de aztán olvass nekem!

low-and-slow-zeberka

Tegnap jött szembe az index.hu cikke, amiben bemutatják, hogy hogyan loptak el nemrég egy kulcs nélküli nyitású Porsche Cayenne-t. Többször olvastam már hasonlót és minden egyes esetben az egekbe szökik tőle a vérnyomásom. Ez a poszt egyrészt segít megérteni, hogy miért, másrészt megpróbál egy kis kriptográfiai alapismeretet ültetni a fejedbe.

Egész pontosan attól leszek ideges, hogy látom, ahogy a sokmilliós autókba a gyártók még mindig képtelenek az autólopást valóban ellehetetlenítő technológiát beépíteni. Ha elolvastad az indexes cikket, abból kiderült, hogy a tolvajok lényegében lehallgatják az autó és a kulcs közötti kommunikációt, valamint a netről beszerzik a változó kódot léptető algoritmust és azzal meg egy korábban lehallgatott kulccsal az új kulcsot kiszámolva nyitják ki a kiszemelt járgányt.
Na de ha ez ilyen egyszerű, akkor miért nem lopják el az összes pénzed, amikor online bankolsz? Az interneten küldözgetsz mindenfélét, ott miért ne hallgatódzhatna a tolvaj és miért ne számoltathatná ki a következő e-bank belépésedhez szükséges kulcsot csak úgy, ahogy az indexes cikkben látott autótolvajok csinálták? Hát azért, mert az autógyártókkal ellentétben a bank nem _szarik_ a biztonságra és megfelelő azonosítási technikát használ!

Titkosítsunk

A kocsikulcs és az kocsi közti kommunikáció során a gonosz tolvaj egyrészt hallgatódzik, másrészt hozzáfér a kommunikációt végző protokollhoz (hiszen vette a neten a kínaiaktól egy szoftver formájában). Valahogy azt kell megoldanunk, hogy a tolvaj ne tudjon a kocsi által értelmezhető üzenetet gyártani, illetve amit lehallgat, azt se értse. Erre megoldás az asszimetrikus titkosítás.

Hogy könnyebben értsük a magyarázatot, nevezzük át a résztvevőket: legyen a kocsi Alice, a kocsikulcs Bob, a hallgatódzó tolvaj pedig Eve.

A titkosításhoz kulcsokra lesz szükségünk, mégpedig résztvevőnként két darabra, egy nyilvános és egy privát kulcsra (a két kulcs nem számítható ki egymásból). Ezekkel a kulcsokkal fogjuk az üzeneteket titkosítani, illetve visszafejteni. Matekozás nélkül fogadjuk el, hogy létezik olyan algoritmus, amely az üzenetet úgy kódolja az egyik kulccsal, hogy az ily módon kódolt üzenet csak a másik kulccsal fejthető vissza.

Ha tehát Alice nyilvános kulcsát odaadjuk Bobnak és Bob nyilvános kulcsát Alice-nak, akkor már meg is vagyunk:

  • Alice Bobnak szánt üzenetét a Bob nyilvános kulcsával kódolja, amit a Bob a saját privát kulcsával dekódol
  • Bob Alicenak szánt üzenetét Alice nyilvános kulcsával kódolja, amit Alice a saját privát kulcsával dekódol

Így, amennyiben egyik privát kulcs sem kerül Eve kezébe, hiába hallgatja le a kommunikációt, nem tudja dekódolni azt, hiába van a kódoló/dekódoló algoritmus a birtokában (nota bene: egy titkosító algoritmus erejét soha nem jelentheti az, hogy az algoritmus maga mennyire ismert). Mindez lerajzolva:
public key encryption
Forrás: Wikipedia

Hol kapható ez az extra?

Számomra a legmeglepőbb, hogy a fent leírt technológiát kínáló biztonságot egyetlen autógyártó sem kínálja, sem alapáron, sem extraként. Másfélmillióért vehetsz adaptív ledes fényszórókat, fizethetsz felárat azért, hogy az autód beparkoljon helyetted, de hogy asszimetrikus titkosítás védje az ajtózárad, arra valahogy nincs kipipálható opció az extralistán. 3rdparty megoldás szerencsére többféle is van: BLUE16, Cerbeos.

Átállás az új CIB mobilalkalmazásra

Pár napja kaptam egy mailt a CIB Banktól, hogy kijött az új, színes-szagos mobilalkalmazásuk, váltsak, ha szeretnék. A váltáshoz kérni kell egy visszahívást amit megtettem és kb. egy nap múlva hívtak is. Mivel az email elég kevés részletet tartalmazott, plusz a visszahívás során derült csak ki pár fontos dolog, gondoltam megosztom itt, hátha másnak is hasznára válik:

  • Ha váltasz, az új alkalmazás által kezelt számlá(k)hoz az új mobil alkalmazás gyártja az OTP tokent az új mobilappon belüli használathoz is és a desktop Java applet azonosításához is. A régi app az OTP tokent netkapcsolat nélkül gyártotta, az új mobilappnál viszont kell a tokengyártáshoz az internetkapcsolat. Ez akkor jelenthet problémát, ha külföldön vagy egy desktop gép előtt és nem tudsz netet adni a mobilodnak.
  • Az alkalmazás csak a magán folyószámlák kezelését támogatja, céges bankszámlákat talán majd jövőre. Ha mindkettővel rendelkezel, akkor a céges számláid authentikációjához marad a korábban is élő token.
  • Amennyiben több magán folyószámla kezelését akarod megoldani az új mobil alkalmazásban és nem mindegyiknek te vagy az elsődleges tulajdonosa (=család egyéb számlái), úgy ezt csak úgy tudják elvégezni, hogy az aktiváció során a nem általad tulajdonolt számlákat a CIB24 telefonos azonosítóval authentikálod. Ha ez nem megy, akkor a saját számlá(i)d kerülnek bele az új mobilappba egész addig, amíg ezt az authentikációt el nem végzed.
  • Az új mobilapp aktiválásához szükség lesz a személyid számára és lejárati dátumára, illetve a bank által ismert személyes adataidra.

Hirtelen ennyi. Nekem sajna ez több szempontból nem felel még meg, úgyhogy maradok régi auth token user.

Mac workflow: Alfred dict.cc translation

Azonnali fordításhoz (=nem akarom levenni a billentyűzetről a kezem ahhoz, hogy lefordítsak egy szót) jó ideig nagy örömmel használtam a Thomas Hempel féle Alfred Google Translate workflow-t, ám a Google egy ideje DDOS attacknak veszi a workflow ismétlődő lekérdezéseit és ez azt eredményezi, hogy viszonylag gyorsan kizár a szolgáltatásból egy teljes napra. Nem volt mese, más fordító megoldás után kellett nézni - így akadtam rá a dict.cc-re.

Innen már csak pár lépés volt Raphael Baron dict.cc-hez írt Python kódja, onnan meg Thomas Hirsch Alfredre szabott workflow-ja.
Thomas megoldása sajna bedrótozta a workflowba, hogy az angol->német irányban fordítson, viszont a dict.cc angolról és németről számos más nyelvre képes fordítani, így csak egy picit kellett megpiszkálni a workflowt ahhoz, hogy angol<->magyar és angol<->lengyel irányokban is fordítson:

dict_cc-en-hu

dict_cc-hu-en

dict_cc-en-pl

dict_cc-pl-en

Újabb forrás->cél nyelv hozzáadásához csak újabb script filtert kell létrehozni:

dict_cc-definitions

amiben csak ezeket kell cserélgetned:

dict_cc-script-filter-details

A workflow-t szedheted tőlem, vagy a github forkból.

Mese az Excelről és a context menüről

TL;DR: 2010-es Excelnél újabb verzióban soha ne használd a Workbook_SheetBeforeRightClick() event handlert arra, hogy saját CommandBart hozz létre - helyette ott a Custom UI editor for Microsoft Office, amivel ugyan csak bedrótozott hierarchiát tudsz csinálni, viszont cserébe nem fagy majd random szénné alatta a host környezet.

A dolog úgy indult, hogy egy Office update után elkezdett furán viselkedni a VBA kód pár táblában. Jó szokás szerint a hibajelenségnek semmi köze nem volt a hiba okához, a Microsoftos alkalmazásnak pedig esze ágában sem volt bármiféle notificationt küldeni, hogy neki XY kóddarabbal lenne baja, sokkal inkább a számukra már sokszor bevált utat választba, nemes egyszerűséggel vagy rommá fagyasztotta a futtató környezetet, vagy a teljes Excel UI elfelejtett a végfelhasználóval kommunikálni. Mutatom:

Excel 2010+ event handler madness from Gabor Penoff on Vimeo.

A videóban jól látszik, hogy a testData tábla kiválasztása után az megnyílik, majd az Excel előbb mintha elfelejtené a screent update-elni, később viszont teljesen meggárgyul és a saját UI elemei is megszűnnek működni.

Nézzük végig, mi történik belül. A 2. kattintásra a standard context menünek kellene előbújnia, azonban én ezt elkapom és a saját cuccaimat pakolom a gyári menü helyére. Mindez úgy történik, hogy a Workbook_SheetBeforeRightClick() event handlert használom:

Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Excel.Range, Cancel As Boolean)
    rightClickMenuShow (rightClickMenuTitle)
    Cancel = RightClickCancel
End Sub

A rightClikMenuShow() törli az előző custom menüt, majd újra létrehozza és megjeleníti:

Sub rightClickMenuShow(rightClickMenuName As String)
    RightClickCancel = True
    Call rightClickMenuDelete(rightClickMenuName)
    Call rightClickMenuCreate(ActiveSheet)
    CommandBars(rightClickMenuTitle).ShowPopup
End Sub

A törlés így néz ki:

Sub rightClickMenuDelete(rightClickMenuName As String)
    Dim bar As CommandBar
 
    For Each bar In CommandBars
        If UCase(Trim(bar.Name)) = UCase(Trim(rightClickMenuTitle)) Then bar.Delete
    Next bar
End Sub

Az új menü létrehozása pedig így:

Sub rightClickMenuCreate(S_Caller As Worksheet)
    Dim rightClickMenuName As String
    Dim rightClickMenuIndex As Long
 
    rightClickMenuName = rightClickMenuTitle
    Call rightClickMenuDelete(rightClickMenuName)
    Application.CommandBars.Add Name:=rightClickMenuName, Position:=msoBarPopup
 
    rightClickMenuIndex = 0
    rightClickMenuIndex = rightClickMenuIndex + 1
    CommandBars(rightClickMenuName).Controls.Add Type:=msoControlButton, Before:=rightClickMenuIndex
    With CommandBars(rightClickMenuName).Controls(rightClickMenuIndex)
        .FaceId = 263
        .Style = msoButtonIconAndCaption
        .Caption = "Excel's &Default Shortcut Menu"
        .OnAction = "ShowDefaultRightClickMenu"
    End With
 
    rightClickMenuIndex = rightClickMenuIndex + 1
    CommandBars(rightClickMenuName).Controls.Add Type:=msoControlButton, Before:=rightClickMenuIndex
    With CommandBars(rightClickMenuName).Controls(rightClickMenuIndex)
        .Style = msoButtonCaption
        .Caption = "Freeze me please"
        .OnAction = "myTestSub"
        .BeginGroup = True
    End With
End Sub

Röviden ennyi a jobb klikkes menüből a myTestSub() makrót elindító event handler mechanizmus. Miután ebben hozzá nem nyúlok a képernyő frissítését szabályozó Application.ScreenUpdating metódushoz, nézzük meg, mit csinál a myTestSub():

Sub myTestSub()
    Dim f As Variant
 
    f = Application.GetOpenFilename
    If f = False Then
        MsgBox "No file selected."
    Else
        Workbooks.Open Filename:=f, ReadOnly:=True
    End If
End Sub

Láthatóan ennek sincs köze a ScreenUpdating-hez, mégis elpusztul tőle az Excel.
Miután a probléma nyilván nem egy ilyen ~20 soros toolban jött elő, pár órát elvett az életemből mire rájöttem, hogy az 2010-es verziónál frissebb Exceleknek azzal van baja, ahogyan én a right click menüt újradefiniálom a Workbook_SheetBeforeRightClick() event handlerben egy CommandBars(rightClickMenuTitle).ShowPopup() hívással. A helyes megoldás ilyenkor az, hogy ezt a popup generátort úgy ahogy van kidobod és létrehozol egy XML-t, ami a fenti két eljárás meghívásához legyártja majd az UI eleme(ke)t a jobb klikkre megjelenő context menüben:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
    <contextMenus>
        <contextMenu idMso="ContextMenuCell">
            <menu id="appMenu" label="engine" insertBeforeMso="Cut">
                <button id="item_id1" label="(Do not) freeze me please" onAction="myTestSub"/>
            </menu>
        </contextMenu>
    </contextMenus>
</customUI>

Ebben az esetben azonban ne felejtsd el, hogy fel kell készíteni a hívott rutinodat az IRibbonControl paraméter fogadására:

Sub myTestSub(control As IRibbonControl)

Tanulság nincs, csak ledokumentáltam 4 óra őrjöngés után a megoldást.

JSON adatbányászat shellben

TL;DR: ha stock OS X alatt shell scriptben JSON-t akarsz parse-olni, jsc-vel csináld.

A probléma

Van egy Alfred workflow-m, amivel villámgyorsan át tudom állítani a Transmission torrent kliens speed limitjét - ez a script a bele.

Ehhez akartam olyat, hogy amint az Alfred querybe beírom a script filer kulcsszavát, azonnal jelenjen meg, hogy mennyi az aktuális speed limit a Transmission kliensben.

A megoldás: 1/3 (eFi)

Először abban reménykedtem, hogy egy Google search majd azonnal ontja magából a találatokat a "parse JSON in bash"-re, de amiket talált, abból egyik sem tetszett igazán, így aztán benga favágó módjára kikapáltam az engem érdeklő infót, duplán regexpelve (mint az állatok):

#!/bin/sh
## guess Transmission's speed limit
 
USER=yourUserName
PASS=yourPassword
server=http://yourTransmissionHostIP
SPEED=$1
 
curlout=$(curl -u $USER:$PASS ${server}:9091/transmission/rpc 2>/dev/null)
regex='(X-Transmission-Session-Id\: )([^<]*)'
 
if [[ $curlout =~ $regex ]]; then
    sessionid=${BASH_REMATCH[2]}
else
    exit 1
fi
 
data='{"method": "session-get"}'
R=$(curl -H $USER:$PASS ${server}:9091/transmission/rpc -d "$data" -H "X-Transmission-Session-Id: $sessionid")
 
ASD_ENABLED=`echo "$R" | grep -o -e '\"alt\-speed\-enabled\":[a-z]*'`
ASD_ENABLED=`echo "$ASD_ENABLED" | grep -o -e '[a-z]*$'`
 
ASD=`echo "$R" | grep -o -e '\"alt\-speed\-down\":[0-9]*'`
ASD=`echo "$ASD" | grep -o -e '[0-9]*$'`
 
SLD_ENABLED=`echo "$R" | grep -o -e '\"speed\-limit\-down\-enabled\":[a-z]*'`
SLD_ENABLED=`echo "$SLD_ENABLED" | grep -o -e '[a-z]*$'`
 
SLD=`echo "$R" | grep -o -e '\"speed\-limit\-down\":[0-9]*'`
SLD=`echo "$SLD" | grep -o -e '[0-9]*$'`
 
echo '<?xml version="1.0"?>'
echo '<items>'
echo " <item uid='tspd' arg='$SPEED' valid='yes'>"
echo " <title>Set Transmission speed limit</title>"
if [ "$ASD_ENABLED" = "true" ]
then
	echo " <subtitle>Current speed limit: $ASD kbps</subtitle>" 
else
	if [ "$SLD_ENABLED" = "true" ]
	then
		echo " <subtitle>Current speed limit: $SLD kbps</subtitle>" 
	else
		echo " <subtitle>Currently no speed limit is set</subtitle>" 
	fi
fi
echo ' <icon>speed-limit.png</icon>'
echo '</item>'
echo '</items>'

A megoldás: 2/3 (fds)

Mennyivel szebb lenne ez egy JSON parserrel!
Eltelt pár óra és Fazekas "fds" Dani barátom megjelent, majd kettő perc múlva kirázta a kisujjából ezt:

JSON='{"efi":24,"csokijat":42,"mar":242,"elvittek":666,"fene":[1,2,3,4]}'
/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc -e "debug(JSON.parse(readline())['fene'][2])" <<< "$JSON"

Script az script, ez meg parsol, úgyhogy ezért INSTANT CSOKI jár.

A megoldás: 3/3 (fds)

fds a posztot látva azt mondta, hogy szerinte nem dolgozott meg a megacsokiért, de ha adnék egy Transmission kimenetet amit a curl leszippant, akkor faragna egy csinosabb verziót. A maximalizmusát már jól ismerve meg nem fosztottam volna a világot az új változattól, úgyhogy azonnal ment az output.
Nem is lenne fds, ha nem csinálta volna meg azonnal jsc, php, python és ruby használatával is az egészet (azért "csak" ennyi interpreterrel, mert ezek érhetők el a gyári OS X alól 2016 januárjában). A hozzám hasonló bolondok biztosan fülig érő szájjal olvassák a scriptet:

#!/bin/bash
 
## guess Transmission's speed limit
 
USER="yourUserName"
PASS="yourPassword"
server="http://yourTransmissionHostIP"
SPEED="$1"
JSONPARSER="jsc"
 
curlout=$(curl -u $USER:$PASS ${server}:9091/transmission/rpc 2>/dev/null)
regex='(X-Transmission-Session-Id\: )([^<]*)'
 
if [[ $curlout =~ $regex ]]; then
    sessionid=${BASH_REMATCH[2]}
else
    exit 1
fi
 
data='{"method": "session-get"}'
R=$(curl -H $USER:$PASS ${server}:9091/transmission/rpc -d "$data" -H "X-Transmission-Session-Id: $sessionid")
 
getargument() {
	local ret
 
	case "$JSONPARSER" in
		jsc)
			ret=$(2>&1 /System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc -e "debug(JSON.parse(readline())['arguments']['$2'])" <<< "$1")
			ret="${ret#-->* }"
			;;
		php)
			ret=$(php -nr "echo json_encode(json_decode(file_get_contents('php://stdin'), true)['arguments']['$2']);" <<< "$1")
			;;
		python)
			ret=$(python -c "import json,sys
print(json.dumps(json.load(sys.stdin)['arguments']['$2']))" <<< "$1")
			;;
		ruby)
			ret=$(ruby -e "require 'json'
puts JSON.parse(STDIN.read)['arguments']['$2']" <<< "$1")
			;;
	esac
 
	echo "$ret"
}
 
ASD_ENABLED=$(getargument "$R" "alt-speed-enabled")
ASD=$(getargument "$R" "alt-speed-down")
SLD_ENABLED=$(getargument "$R" "speed-limit-down-enabled")
SLD=$(getargument "$R" "speed-limit-down")
 
echo '<?xml version="1.0"?>'
echo '<items>'
echo $'\t''<item uid="tspd" arg="'"$SPEED"'" valid="yes">'
echo $'\t'$'\t'"<title>Set Transmission speed limit</title>"
if [ "$ASD_ENABLED" = "true" ]; then
	echo $'\t'$'\t'"<subtitle>Current speed limit: $ASD kbps</subtitle>" 
else
	if [ "$SLD_ENABLED" = "true" ]; then
		echo $'\t'$'\t'"<subtitle>Current speed limit: $SLD kbps</subtitle>" 
	else
		echo $'\t'$'\t'"<subtitle>Currently no speed limit is set</subtitle>" 
	fi
fi
echo $'\t'$'\t''<icon>speed-limit.png</icon>'
echo $'\t''</item>'
echo '</items>'

Persze ennyivel nem érte be, megmérte, hogy melyik verzió mennyi időt zabál el az életemből:

for p in jsc php python ruby; do
	echo -n "$p: "
	JSONPARSER="$p"
	OUT=$(( time -p (
		ASD_ENABLED=$(getargument "$R" "alt-speed-enabled")
		ASD=$(getargument "$R" "alt-speed-down")
		SLD_ENABLED=$(getargument "$R" "speed-limit-down-enabled")
		SLD=$(getargument "$R" "speed-limit-down")
		echo "${ASD_ENABLED}|${ASD}|${SLD_ENABLED}|${SLD}"
	) ) 2>&1)
	echo -n $(tail -n 3 <<< "$OUT" | head -n 1 | cut -d ' ' -f 2)s
	echo ' '$(head -n 1 <<< "$OUT")
done
exit

Az eredmény az, hogy a jsc mindent lever:

jsc: 0.04s false|10|true|500
php: 0.25s false|10|true|500
python: 0.11s false|10|true|500
ruby: 0.23s false|10|true|500

Maximalista grafikusnak megismert Rack barátom szokta azt mondani az árajánlatot sokalló ügyfélnek, hogy "de minden pixel a helyén van". Nos, nekem Dani ugyanez a szerethető fanatikus coderben. Le vagyok nyűgözve, mint mindig :)

Excel VBA: Application.Evaluate – Error (2015|2029)

Ha legközelebb egy formulát akarsz kiértékeltetni a VBA engine Application.Evaluate() metódusával és a rohadék a nem túl beszédes "Error 2015" vagy "Error 2029" stringeket adná vissza cserébe, akkor ne a formulákban keresd a hibát, hanem azt nézd meg, hogy a kiértékelés forrásaként használt képlet és az aktív workbook referenciastílusa megegyezik-e. Ha nem, akkor állítsd át az

Application.ReferenceStyle = (xlA1|xlR1C1)

értékadással és problem solved, a redmondi felelősök meg süllyedjenek el szégyenükben a gusztustalan workaroundjukkal együtt.