diff --git a/src/cam.cpp b/src/cam.cpp
index 7414a8e9112922e95f8926dc991e6ec27c0542e7..67d599e0b60afe162cc56e7b0918295ba801f9b4 100644
--- a/src/cam.cpp
+++ b/src/cam.cpp
@@ -1,4 +1,5 @@
 #include "cam.h"
+#include "iprinter.h"
 #include "utils.h"
 #include "frameobserver.h"
 
@@ -15,14 +16,12 @@ using State = Cam::State;
 using namespace VmbCPP;
 using namespace std::chrono;
 
-//xxx
-// Cam(QString name, QString ip) : IPrinter(),
-// _cam(CameraPtr(new Camera(name.toStdString(), ip.toStdString()))),
-
-Cam::Cam(CameraPtr pCamera) : IPrinter(),
-_cam(pCamera),
+Cam::Cam(QString name, QString ip) : IPrinter(),
+_cam(nullptr),
+_name(name),
+_ip(ip),
 _id(""),
-_state(closed),
+_state(disconnected),
 _frames(FramePtrVector(threadsPerCam())),
 _payloadSize(0LL),
 _pixelFormat(""),
@@ -30,22 +29,40 @@ _timer(new QTimer(this))
 {
 	_timer->setSingleShot(true);
 	connect(_timer, SIGNAL(timeout()), this, SLOT(stopRecording()));
-	id();
-
+	// id();
 }
 
-// Copy constructor
-Cam::Cam(const Cam& other) :
-IPrinter(),
-_cam(other._cam),
-_id(other._id),
-_state(other._state),
-_frames(other._frames),
-_payloadSize(other._payloadSize),
-_pixelFormat(other._pixelFormat)
-{
-	qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "copy constructor";
-}
+
+//xxx add ip and name
+// Cam::Cam(CameraPtr pCamera) : IPrinter(),
+// _cam(pCamera),
+// _name(""),
+// _ip(""),
+// _id(""),
+// _state(closed),
+// _frames(FramePtrVector(threadsPerCam())),
+// _payloadSize(0LL),
+// _pixelFormat(""),
+// _timer(new QTimer(this))
+// {
+// 	_timer->setSingleShot(true);
+// 	connect(_timer, SIGNAL(timeout()), this, SLOT(stopRecording()));
+// 	id();
+
+// }
+
+// // Copy constructor
+// Cam::Cam(const Cam& other) :
+// IPrinter(),
+// _cam(other._cam),
+// _id(other._id),
+// _state(other._state),
+// _frames(other._frames),
+// _payloadSize(other._payloadSize),
+// _pixelFormat(other._pixelFormat)
+// {
+// 	qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "copy constructor";
+// }
 
 Cam::~Cam()
 {
@@ -56,6 +73,16 @@ Cam::~Cam()
 	// close() should be called automatically, when the last shared_ptr to the camera is destroyed
 }
 
+QString Cam::name() const
+{
+	return _name;
+}
+
+QString Cam::ip() const
+{
+	return _ip;
+}
+
 QString Cam::id()
 {
 	if( _id.isEmpty() )
@@ -67,6 +94,11 @@ QString Cam::id()
 	return _id;
 }
 
+void Cam::setState(const State& state)
+{
+	_state = state;
+}
+
 State Cam::state() const
 {
 	return _state;
@@ -74,14 +106,20 @@ State Cam::state() const
 
 void Cam::open()
 {
+	if(_state != closed)
+		return error("cant open " + stateToString(_state) + " cam");
+
 	f(_cam->Open( VmbAccessModeFull ),"open cam #"+_id);
-	//state change will be handled by CamObserver::CameraStateChanged
+	//state change will be handled by CamObserver::CameraStateChanged > Core::onCameraChanged > Cam::onChanged
 }
 
 void Cam::close()
 {
+	if(_state != opened)
+		return error("cant close " + stateToString(_state) + " cam");
+
 	f(_cam->Close(),"close cam #"+_id);
-	//state change will be handled by CamObserver::CameraStateChanged
+	//state change will be handled by CamObserver::CameraStateChanged > Core::onCameraChanged > Cam::onChanged
 }
 
 /* Does:
@@ -99,6 +137,9 @@ void Cam::close()
 */
 void Cam::startRecording(seconds dur)
 {
+	if(_state != opened)
+		return error("cant start recording, when cam is " + stateToString(_state));
+
 	try
 	{
 		FeaturePtr pFeature;
@@ -154,6 +195,9 @@ void Cam::startRecording(minutes dur)
 */
 void Cam::stopRecording()
 {
+	if(_state != recording)
+		return error("cant stop recording, when cam is " + stateToString(_state));
+
 	_timer->stop();
 
 	FeaturePtr pFeature;
@@ -176,7 +220,10 @@ void Cam::stopRecording()
 // id,name,model,serial,interfaceID,state
 QString Cam::info()
 {
-	QString camInfo;
+	QString camInfo = _name + DELIM + _ip + DELIM;
+	if( state() == Cam::disconnected )
+		return camInfo + "disconnected";
+
 	try
 	{
 		std::string str;
@@ -224,18 +271,29 @@ QString Cam::stateToString(const State& state)
 	}
 }
 
-void Cam::toggleOpenClose()
+void Cam::onChanged(UpdateTriggerType type)
 {
-	// qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << stateToString(_state);
-	if( _state == opened )
-		_state = closed;
-	else if ( _state == closed )
-		_state = opened;
-	else
-		error("toggleOpenClose: cam state is neither closed nor opened");
-}
-
-void Cam::onCameraDisconnected()
-{
-	_state = disconnected;
+	switch (type)
+	{
+		case UpdateTriggerType::UpdateTriggerPluggedIn:
+			IPrinter::info(name()+" connected");
+			setState(closed);
+			//_cam ptr set in core
+			break;
+		case UpdateTriggerType::UpdateTriggerPluggedOut:
+			IPrinter::info(name()+" disconnected");
+			setState(disconnected);
+			_cam.reset();
+			break;
+		case UpdateTriggerType::UpdateTriggerOpenStateChanged:
+
+			qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "state changed" << stateToString(_state);
+			if( _state == opened )
+				_state = closed;
+			else if ( _state == closed )
+				_state = opened;
+			break;
+		default:
+			error("onChanged: unknown trigger type");
+	}
 }
diff --git a/src/cam.h b/src/cam.h
index 6268817df6c499312be09f276e34afaf796ef14e..64698ecd91e190c61e2e11afb00a3b5230a57b1e 100644
--- a/src/cam.h
+++ b/src/cam.h
@@ -15,6 +15,7 @@ using VmbCPP::CameraPtr;
 using VmbCPP::FramePtr;
 using VmbCPP::FeaturePtr;
 using VmbCPP::FramePtrVector;
+using VmbCPP::UpdateTriggerType;
 
 using std::chrono::minutes;
 using std::chrono::seconds;
@@ -37,26 +38,31 @@ public:
 	};
 
 	// const QString& name, const int& nThreads
-	Cam(CameraPtr pCamera);
 	Cam(QString name, QString ip);
-	Cam(const Cam&);
+	// Cam(CameraPtr pCamera);
+	// Cam(const Cam&);
 	~Cam();
 
 	QString id();
+	QString name() const;
+	QString ip() const;
+
 	State state() const;
+	void setState(const State&);
+
 	static QString stateToString(const State&);
-	void toggleOpenClose();
+	void onChanged(UpdateTriggerType);
 
 	void open();
 	void close();
 	void startRecording(minutes dur);
 	void startRecording(seconds dur); //can use literals "1s, 1min"
 	QString info();
-	inline CameraPtr getCameraPtr() const { return _cam; }
+	inline CameraPtr getCameraPtr() { return _cam; }
+	inline void setCameraPtr( CameraPtr pCamera ) { _cam = pCamera; }
 
 public slots:
 	void stopRecording();
-	void onCameraDisconnected();
 
 private:
 	CameraPtr _cam;
diff --git a/src/camobserver.cpp b/src/camobserver.cpp
index 125cdc368ce1dfbc92a5da5e781aec0a4fb29363..8ac90563d1f3641b77b98df4816fa42951225067 100644
--- a/src/camobserver.cpp
+++ b/src/camobserver.cpp
@@ -7,16 +7,8 @@
 
 using namespace VmbCPP;
 
-void CamObserver::CameraListChanged(CameraPtr pCam, UpdateTriggerType reason)
+void CamObserver::CameraListChanged(CameraPtr pCam, UpdateTriggerType type)
 {
-	if( UpdateTriggerPluggedIn == reason || UpdateTriggerPluggedOut == reason )
-	{
-		// qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "";
-		emit cameraListChanged();
-	}
-	else // UpdateTriggerOpenStateChanged
-	{
-		emit cameraStateChanged(pCam);
-		// qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "";
-	}
+	qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__;
+	emit cameraChanged(pCam,type);
 }
diff --git a/src/camobserver.h b/src/camobserver.h
index b0e4065390576c12ae8d67b629b19955a1da22c2..ee401e29681a0ae7328bbdc783072b14db66e550 100644
--- a/src/camobserver.h
+++ b/src/camobserver.h
@@ -12,11 +12,13 @@ class CamObserver : public QObject, public ICameraListObserver
 	Q_OBJECT
 
 signals:
-	void cameraListChanged();
-	void cameraStateChanged(CameraPtr);
+	void cameraChanged(CameraPtr, UpdateTriggerType);
 
 public:
 	void CameraListChanged(CameraPtr, UpdateTriggerType);
+
+	// virtual ~CamObserver() { qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << ""; }
+
 };
 
 }
diff --git a/src/cmd/console.cpp b/src/cmd/console.cpp
index e1ccf04202872aa3f44eff8c3f363fc2cd8c5ad6..1a8dfcb340a32a199ac7c6162d1f16d506289b46 100644
--- a/src/cmd/console.cpp
+++ b/src/cmd/console.cpp
@@ -91,11 +91,12 @@ void Console::printHelp()
 	<< "h: print this help"
 	<< "1-9: select camera"
 	<< "d: change duration of recording"
-	<< "c: close current camera"
 	<< "o: open current camera"
+	<< "c: close current camera"
 	<< "r: start recording"
-	<< "t: stop recording"
+	<< "s: stop recording"
 	<< "l: list available cameras"
+	<< "k: deteKt cameras"
 	<< "v: print versions"
 	<< "q: quit"
 	// XXX add new func
@@ -137,10 +138,6 @@ void Controller::onKeyPressed(const QChar& key)
 	switch (key.unicode())
 	{
 		// XXX add new func
-		case 'h':
-			console->printHelp();
-			break;
-
 		case 'd':
 			console->print("Enter duration in seconds: ");
 			getDur = true;
@@ -158,11 +155,15 @@ void Controller::onKeyPressed(const QChar& key)
 			emit listCams();
 			break;
 
+		case 'k':
+			emit detectCams();
+			break;
+
 		case 'r':
 			emit startRecording();
 			break;
 
-		case 't':
+		case 's':
 			emit stopRecording();
 			break;
 
@@ -173,6 +174,10 @@ void Controller::onKeyPressed(const QChar& key)
 		case 'q':
 			qApp->quit();
 			break;
+
+		default:
+			console->printHelp();
+			break;
 	}
 }
 
diff --git a/src/cmd/console.h b/src/cmd/console.h
index 8ee9c7e1b63b6a1a5d9952c9533dad12b4574e7e..bb680ab637f7704307101e9e53b2318a78a19d32 100644
--- a/src/cmd/console.h
+++ b/src/cmd/console.h
@@ -60,6 +60,7 @@ class Controller : public QObject
 
 		// to core
 		void listCams();
+		void detectCams();
 		void openCam();
 		void closeCam();
 		void cam(int);
diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp
index 882b7dfb3db6a2d137d555f35bccebcfa4cec498..5c4c5aa64b4e3bdc146794a23b124d9db51fc5b6 100644
--- a/src/cmd/main.cpp
+++ b/src/cmd/main.cpp
@@ -25,6 +25,7 @@ int main(int argc, char *argv[])
 
 	//ui (controller) -> vmb (core)
 	QObject::connect(&controller, &Controller::listCams,			&core, &Core::listCams);
+	QObject::connect(&controller, &Controller::detectCams,		&core, &Core::detectCams);
 	QObject::connect(&controller, &Controller::openCam, 			&core, &Core::openCam);
 	QObject::connect(&controller, &Controller::closeCam, 			&core, &Core::closeCam);
 	QObject::connect(&controller, &Controller::cam, 				&core, &Core::cam);
diff --git a/src/core.cpp b/src/core.cpp
index c7f60ed5c285372f88cef9f10785ae5e41445485..2bee444774ddd2e2a5abc32864fb65a7bbeb39d1 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -6,6 +6,7 @@
 
 #include <chrono>
 #include <iostream>
+#include <list>
 #include <vector>
 
 #include <VmbC/VmbCommonTypes.h>
@@ -17,14 +18,14 @@
 #include <QThread>
 #include <QTimer>
 
-
 using namespace VmbCPP;
-using namespace std::chrono_literals; //seconds, minutes, hours
+using namespace std::chrono_literals; //ms, s, m, h
 
 Core::Core() : IPrinter(),
 	_sys( VmbSystem::GetInstance() ), // create and get Vimba singleton
-	_cameras( CamPtrVector() ),
-	_recDuration( 6s ) //default
+	// _cameras( CamPtrVector() ),
+	_recDuration( 6s ), //default
+	_camObserver( new CamObserver )
 {
 	QTimer::singleShot(0, this, SLOT(init())); //delayed init to allow connections to be established -> print/error signals!
 }
@@ -36,24 +37,22 @@ void Core::init()
 
 	print("threads",QThread::idealThreadCount());
 
-	auto camObserver = new CamObserver();
-	connect( camObserver, SIGNAL(cameraListChanged()), this, SLOT(listCams()) ); //listcams calls updateCams!
-	connect( camObserver, SIGNAL(cameraStateChanged(CameraPtr)), this, SLOT(toggleCamState(CameraPtr)) ); //
 
-	f(_sys.RegisterCameraListObserver(ICameraListObserverPtr(camObserver)), "register cam observer");
+	f(_sys.RegisterCameraListObserver(ICameraListObserverPtr(_camObserver)), "register cam observer");
+	connect( _camObserver, SIGNAL(cameraChanged(CameraPtr,UpdateTriggerType)), this, SLOT(onCameraChanged(CameraPtr,UpdateTriggerType)) ); //listcams calls updateCams!
 
 	//parse config file
 	QList<QPair<QString, QString>> parsedCameras;
 	parseConfig(configFile(), parsedCameras);
-	print("parsed cams:");
+
+	//add to cam list
 	for ( auto cam : parsedCameras )
 	{
-		print({cam.first,cam.second});
+		auto pcam = std::make_shared<Cam>(cam.first,cam.second);
+		_cameras.push_back(pcam);
 	}
 
-
-//XXX
-	//ping each cam and if its exists create camPtr
+	detectCams();
 	// listCams();
 }
 
@@ -61,89 +60,41 @@ void Core::init()
 Core::~Core()
 {
 	qDebug() << __FUNCTION__ << "():" << __LINE__;
-
-	_sys.Shutdown();
+	_sys.Shutdown(); // will delete camObserver
 }
 
 // update & sync camera vectors
-void Core::updateCameras()
+void Core::detectCams()
 {
-	// CameraPtrVector vmbCameras;
-	// if ( f(_sys.GetCameras( vmbCameras ), "update cameras") )
-	// 	return;
-
-//XXX
-	// if( VmbErrorSuccess == _sys.GetCameraByID( "172.18.227.211", VmbAccessModeFull, camera ) )
-	// {
-	// 	std::cout << "Camera opened" << std::endl;
-	// }
-
-	// if( (int)vmbCameras.size() != ncam() ) //update number of cameras
-	// 	error(QString("Expected %1 cams!").arg(ncam()),errLessCamsThanExpected); //XXX warning
-
-	// // vector< shared_ptr<Camera> > vmbCameras
-	// // vector< shared_ptr<Cam> > _cameras
-
-	// // Add new cameras
-	// for (const auto& vcam : vmbCameras)
-	// {
-	// 	bool found = false;
-	// 	for (const auto& cam : _cameras)
-	// 	{
-	// 		if (cam->getCameraPtr() == vcam)
-	// 		{
-	// 			found = true;
-	// 			break;
-	// 		}
-	// 	}
-	// 	if (!found)
-	// 	{
-	// 		_cameras.push_back(std::make_shared<Cam>(vcam)); //create Cam() from CameraPtr vcam
-	// 		print(QString("cam connected: %1").arg(_cameras.back()->id()));
-	// 	}
-	// }
-
-	// // Remove cameras that are no longer present
-	// auto it = _cameras.begin();
-	// while (it != _cameras.end())
-	// {
-	// 	// qDebug() << "check " << (*it)->id();
-
-	// 	bool found = false;
-	// 	for (const auto& vcam : vmbCameras)
-	// 	{
-	// 		if ((*it)->getCameraPtr() == vcam)
-	// 		{
-	// 			found = true;
-	// 			++it;
-	// 			break;
-	// 		}
-	// 	}
-
-	// 	if (!found)
-	// 	{
-	// 		qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << " !!! ";
-	// 		print({"cam disconnected",(*it)->id()});
-	// 		it = _cameras.erase(it);
-	// 	}
-	// }
-} // now ~Camera() should be called on removed cams. >> triggers camObserver
-
-void Core::toggleCamState(CameraPtr vcam)
+	qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "";
+	for ( auto cam : _cameras )
+	{
+		if( cam->state() == Cam::disconnected )
+		{
+			CameraPtr pcam;
+			if( VmbErrorSuccess == _sys.GetCameraByID( cam->ip().toStdString(), VmbAccessModeFull, pcam ) )
+			{
+				cam->setCameraPtr(pcam); //triggers camobserver changed signal > set state closed
+			}
+		}
+	}
+}
+
+void Core::onCameraChanged(CameraPtr vcam, UpdateTriggerType type)
 {
 	for (const auto& cam : _cameras)
 		if (cam->getCameraPtr() == vcam)
-			return cam->toggleOpenClose();
+			cam->onChanged(type);
+
+	listCams();
 }
 
+
 // update + print camlist
 void Core::listCams()
 {
-	updateCameras();
-	print("cams",_cameras.size());
-
+	// qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "";
 	QStringList allCamInfo;
-	auto idx=0;
 	for ( auto camera : _cameras  )
 	{
 		QString camInfo;
@@ -151,7 +102,6 @@ void Core::listCams()
 			camInfo += " * ";
 		else
 			camInfo += "   ";
-		camInfo += "Cam" + QString::number(++idx) + ": ";
 		camInfo += camera->info();
 
 		allCamInfo << camInfo;
@@ -165,16 +115,19 @@ void Core::listCams()
 
 void Core::openCam()
 {
-	if( cam() )
-		cam()->open();
+	if( !cam() )
+		return;
+
+	cam()->open();
 }
 
 void Core::closeCam()
 {
-	if( cam() )
-		cam()->close();
-}
+	if( !cam() )
+		return;
 
+	cam()->close();
+}
 
 /*
 current camera getter + setter
@@ -185,11 +138,13 @@ CamPtr Core::cam(const unsigned long &idx)
 {
 	static unsigned long curIdx = 0;
 	if( idx != -1UL )
+	{
 		curIdx = idx;
+		listCams(); // avoid endless loop
+	}
 
 	try
 	{
-		// print("set cam",idx+1);
 		return _cameras.at(curIdx);
 	}
 	catch (const std::out_of_range& oor)
diff --git a/src/core.h b/src/core.h
index c7729e3d69f5eeb42478ac813cba363871eaa077..239c100c87f8c6b96ec7f6fe948460f8ea0fe6da 100644
--- a/src/core.h
+++ b/src/core.h
@@ -1,6 +1,8 @@
 #pragma once
 
+#include "VmbCPP/VmbCPPCommon.h"
 #include "cam.h"
+#include "camobserver.h"
 #include "iprinter.h"
 
 #include <QObject>
@@ -10,6 +12,8 @@
 
 namespace VmbCPP { class VmbSystem; }
 using VmbCPP::VmbSystem;
+using VmbCPP::CamObserver;
+using VmbCPP::UpdateTriggerType;
 using std::chrono::seconds;
 
 class Core : public IPrinter
@@ -23,7 +27,8 @@ public:
 
 public slots:
 	void listCams();
-	void toggleCamState(CameraPtr);
+	void detectCams();
+	void onCameraChanged(CameraPtr,UpdateTriggerType);
 	void openCam();
 	void closeCam();
 	// XXX add new func
@@ -38,9 +43,10 @@ private slots:
 	void init();
 
 private:
-	void updateCameras();
 
 	VmbSystem& _sys;
 	CamPtrVector _cameras;
 	seconds _recDuration;
+	CamObserver* _camObserver;
+
 };
diff --git a/src/utils.cpp b/src/utils.cpp
index eb98755ee9e316c7dc9d7b4a738214c57720490a..8c939d927153a5bb5425389c9888eed4fbfbefee 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -193,7 +193,7 @@ QString configFile(QString filename)
 	static QString _filename;
 	if( _filename.isEmpty() )
 	{
-		_filename = filename.isEmpty() ? QCoreApplication::applicationDirPath() + "/cams.json" : filename;
+		_filename = filename.isEmpty() ? QCoreApplication::applicationDirPath() + "/test.json" : filename;
 	}
 	return _filename;
 }
diff --git a/vimbax/api/include/VmbCPP/VmbSystem.hpp b/vimbax/api/include/VmbCPP/VmbSystem.hpp
index 9d791cd0ef37c72e4a6099d08a429b286b232955..69b50fe80807ba986a0d62a9ce6fd0dc46163754 100644
--- a/vimbax/api/include/VmbCPP/VmbSystem.hpp
+++ b/vimbax/api/include/VmbCPP/VmbSystem.hpp
@@ -170,8 +170,9 @@ inline typename std::enable_if<CStringLikeTraits<T>::IsCStringLike, VmbErrorType
     return GetTransportLayerByID(CStringLikeTraits<T>::ToString(id), pTransportLayer);
 }
 
+//XXX added [[gnu::unused]] to get rid of unused warning
 template<class IdType>
-inline typename std::enable_if<CStringLikeTraits<IdType>::IsCStringLike, VmbErrorType>::type VmbSystem::GetCameraByID(const IdType& id, VmbAccessModeType eAccessMode, CameraPtr& pCamera)
+inline typename std::enable_if<CStringLikeTraits<IdType>::IsCStringLike, VmbErrorType>::type VmbSystem::GetCameraByID(const IdType& id,  [[gnu::unused]] VmbAccessModeType eAccessMode, CameraPtr& pCamera)
 {
     static_assert(std::is_same<char const*, decltype(CStringLikeTraits<IdType>::ToString(id))>::value,
                   "CStringLikeTraits<IdType>::ToString(const IdType&) does not return char const*");